所以我只是在c#中使用Task类进行一些实验,并发生以下事情。
这是我调用的方法
static async Task<List<int>> GenerateList(long size, int numOfTasks)
{
var nums = new List<int>();
Task[] tasks = new Task[numOfTasks];
for (int i = 0; i < numOfTasks; i++)
{
tasks[i] = Task.Run(() => nums.Add(Rand.Nex())); // Rand is a ThreadLocal<Random>
}
for (long i = 0; i < size; i += numOfTasks)
{
await Task.WhenAll(tasks);
}
return nums;
}
我这样称呼这个方法
var nums = GenerateList(100000000, 10).Result;
之前我使用任务生成需要4-5秒。在我实现这样的方法后,如果我传递10-20个任务数,生成时间降低到1.8-2.2秒,但是由方法返回的List
具有{numOfTask
1}}其中的元素数量,因此在这种情况下返回10个数字的List
。可能是我写错了。这可能是什么问题。或者可能有另一种解决方案。所有我想要在同一个列表中添加数字的任务很多,因此生成时间至少要快两倍。在此先感谢
答案 0 :(得分:2)
WhenAll
不执行任务;它只是(异步)等待它们完成。您的代码只创建了10个任务,这就是为什么您只获得10个数字。另外,正如@Mauro指出的那样,List<T>.Add
不是线程安全的。
如果要进行并行计算,请使用Parallel
或并行LINQ,而不是async
:
static List<int> GenerateList(int size, int numOfTasks)
{
return Enumerable.Range(0, size)
.AsParallel()
.WithDegreeOfParallelism(numOfTasks)
.Select(_ => Rand.Value.Next())
.ToList();
}
答案 1 :(得分:1)
正如斯蒂芬所解释的那样,你只创造了10个任务。
另外,我相信通用列表上的Add
操作不是线程安全的。您应该使用锁定机制,或者,如果您要定位框架4或更新,请使用thread-safe collections。
答案 2 :(得分:-1)
您要添加到以下循环中的列表中,该循环仅运行10次
for (int i = 0; i < numOfTasks; i++)
{
tasks[i] = Task.Run(() => nums.Add(Rand.Nex())); // Rand is a ThreadLocal<Random>
}
你可以改为
for (int i = 0; i < numOfTasks; i++)
{
tasks[i] = new Task(() => nums.Add(Rand.Nex()));
}