繁体   English   中英

C#多个任务不能并行运行

[英]c# multiple tasks do not run in parallel

我试图创建一个多线程骰子滚动模拟-只是出于好奇心,多线程编程的乐趣,并向其他人展示“随机结果”的效果(许多人不明白,如果您连续六次滚动拉普拉斯骰子,您已经有1、2、3、4、5,则下一卷不是6.)。 为了向他们展示n个骰子与m个骰子的分布,我创建了此代码。

好吧,即使我为程序运行的单线程的每个骰子创建一个新任务,结果也不错。 随着完成时间的快速增长,多线程模拟6个或更多骰子的“成千上万”的重新滚动是合理的。

我从msdn阅读了几个示例,所有示例都表明应该同时运行多个任务。 有人可以给我一个提示,为什么这段代码没有利用很多线程/内核吗? (甚至,当我尝试一次运行400个骰子并重新滚动1000万次时)

首先,我初始化存储结果的锯齿状数组。 第一维:每个骰子1个条目,第二维是每个骰子滚动的眼睛分布。

接下来,我创建一个任务数组,每个任务返回一个结果数组(如上所述,第二个维度)。每个数组都有6个条目,分别代表拉普拉斯W6骰子的每一面。 如果骰子掷出一只眼睛,则第一项[0]增加+1。 因此,您可以直观地看到每个值的滚动频率。

然后,我使用一个普通的for循环启动所有线程。 没有指示等待线程,直到所有线程都启动。

最后,我等待所有人完成并总结结果。 更改没有任何区别

Task.WaitAll(任务); 到Task.WhenAll(tasks);

再说一次我的话:为什么这些代码不占用我CPU的多个核心? 我必须改变什么?

提前致谢!

这是代码:

private void buttonStart_Click(object sender, RoutedEventArgs e)
    {      
        int tries = 1000000;
        int numberofdice = 20   ;
        int numberofsides = 6; // W6 = 6
        var rnd = new Random();

        int[][] StoreResult = new int[numberofdice][];
        for (int i = 0; i < numberofdice; i++)
        {
            StoreResult[i] = new int[numberofsides];
        }

        Task<int[]>[] tasks = new Task<int[]>[numberofdice];


        for (int ctr = 0; ctr < numberofdice; ctr++)
        {

            tasks[ctr] = Task.Run(() =>
            {
                int newValue = 0;
                int[] StoreTemp = new int[numberofsides]; // Array that represents how often each value appeared
                for (int i = 1; i <= tries; i++) // how often to roll the dice
                {
                    newValue = rnd.Next(1, numberofsides + 1); // Roll the dice; UpperLimit for random int EXCLUDED from range 
                    StoreTemp[newValue-1] = StoreTemp[newValue-1] + 1; //increases value corresponding to eyes on dice by +1
                }
                return StoreTemp;
            });
                StoreResult[ctr] = tasks[ctr].Result; // Summing up the individual results for each dice in an array

        }
        Task.WaitAll(tasks);

          // do something to visualize the results - not important for the question

        }
    }

这里的问题是tasks[ctr].Result .Result部分本身会等待函数完成,然后再将结果int数组存储到StoreResult中。 而是在Task.WaitAll之后创建一个新循环以获取结果。

您可以考虑执行Parallel.Foreach循环,而不是为此手动创建单独的任务。

正如其他人指出的那样,当您尝试进行汇总时,您最终只能等待每个任务完成,因此实际上并不是多线程的。

非常重要的注意事项: C#随机数生成器不是线程安全的 (有关此主题的讨论,另请参见此MSDN博客文章 )。 不要在多个线程之间共享同一实例。 文档中

...随机对象不是线程安全的。 如果您的应用从多个线程调用随机方法,则必须使用同步对象来确保一次只有一个线程可以访问随机数生成器。 如果不确保以线程安全的方式访问Random对象,则对返回随机数的方法的调用将返回0。

而且,只是挑剔,使用Task与进行多线程并不是一回事。 实际上,尽管您在这里进行多线程处理,但也可以使用async / await来执行纯异步,非多线程代码。 这主要用于I / O绑定操作,在该操作中创建一个单独的线程只是为了等待结果是没有意义的(但最好是允许调用线程在等待结果的同时做其他工作)。

我认为您在分配给主数组时不必担心线程安全(假设每个线程仅分配给数组中的特定索引,而没有其他人分配给相同的内存位置); 您只需要担心在多个线程同时访问/修改共享可变状态时进行锁定。 如果我正确阅读此文件,则该状态可变状态(但不是共享的可变状态)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM