c#多个任务不会并行运行

c#多个任务不会并行运行,c#,multithreading,parallel-processing,task,C#,Multithreading,Parallel Processing,Task,我试图创建一个多线程骰子滚动模拟——只是出于好奇,多线程编程的乐趣,并向其他人展示“随机结果”的效果(许多人无法理解,如果你连续滚动一个拉普拉斯骰子六次,而你已经有了1、2、3、4、5,那么下一个骰子就不是6)。为了向他们展示n个骰子和m个骰子的分布,我创建了这个代码 好的,结果很好,但即使我为每个骰子创建了一个新任务,程序还是运行单线程。 多线程是合理的,因为完成时间将快速增长,所以可以用6个或更多的骰子模拟“数百万”的重新掷骰 我阅读了msdn中的几个示例,这些示例都表明应该有多个任务同时运

我试图创建一个多线程骰子滚动模拟——只是出于好奇,多线程编程的乐趣,并向其他人展示“随机结果”的效果(许多人无法理解,如果你连续滚动一个拉普拉斯骰子六次,而你已经有了1、2、3、4、5,那么下一个骰子就不是6)。为了向他们展示n个骰子和m个骰子的分布,我创建了这个代码

好的,结果很好,但即使我为每个骰子创建了一个新任务,程序还是运行单线程。 多线程是合理的,因为完成时间将快速增长,所以可以用6个或更多的骰子模拟“数百万”的重新掷骰

我阅读了msdn中的几个示例,这些示例都表明应该有多个任务同时运行。 有人可以给我一个提示,为什么这个代码没有使用很多线程/内核?(甚至不是,当我试着一次运行400个骰子和1000万个重掷时)

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

接下来,我创建一个任务数组,每个任务都返回一个结果数组(第二个维度,如上所述) 每个数组都有6个条目,表示拉普拉斯W6骰子的每一侧。如果掷骰结果为1眼,则第一个项目[0]增加+1。因此,您可以可视化每个值的滚动频率

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

最后,我等待一切结束并总结结果。如果改变,这没有任何区别

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

我的等式是:为什么代码不使用我的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

        }
    }
private void按钮开始单击(对象发送者,路由目标)
{      
整数=1000000;
int numberofdice=20;
int numberofsides=6;//W6=6
var rnd=新随机数();
int[][]StoreResult=新int[numberofdice][];
for(int i=0;i
{
int newValue=0;
int[]StoreTemp=new int[numberofsides];//表示每个值出现频率的数组

对于(int i=1;i这里的问题是
tasks[ctr]。Result
.Result
部分本身在将生成的int数组存储到StoreResult之前等待函数完成。相反,在
Task.WaitAll
之后创建一个新的循环以获得结果。

这里的问题是
tasks[ctr]结果< /代码> .<代码>结果> <代码>部分在将所得INT数组存储到SturrESeLT之前等待函数完成。相反,在Task.< WaitAll >代码>后生成一个新的循环。
正如其他人所指出的,当您尝试聚合此任务时,您只需等待每个单独的任务完成,因此这实际上不是多线程的

非常重要的注意事项:C#随机数生成器(有关此主题的讨论,请参见此)。不要在多个线程之间共享同一实例。从:

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

另外,要挑剔的是,使用
任务
与执行多线程并不是一回事;事实上,在这里执行多线程时,也可以使用async/await执行纯异步、非多线程代码。这主要用于I/O绑定的操作,在这些操作中,创建单独的线程基本上是毫无意义的d只是等待一个结果(但最好允许调用线程在等待结果时执行其他工作)


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

您可以考虑做一个并行的Frach循环,而不是手动为这个任务创建单独的任务。 正如其他人所指出的,当您尝试聚合此任务时,您只需等待每个单独的任务完成,因此这实际上不是多线程的

非常重要的注意事项:C#随机数生成器(有关此主题的讨论,请参见此)。不要在多个线程之间共享同一实例。从:

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

另外,要吹毛求疵的是,使用
任务
与执行多线程并不是一回事;事实上,在这里执行多线程时,也可以执行纯异步、非多线程