在C#中,
如何生成多个线程,然后在返回整个结果集之前依次将结果添加到列表中?
有哪些最佳做法?
到目前为止,我使用ManualResetEvent来表示线程处理最后一个元素的时间。
但是当它返回时,我需要让它们按顺序合并结果集,这样我们就不会遇到返回值列表的争用问题(总结果)。
答案 0 :(得分:1)
如果在产生线程之前知道最终的顺序(你的“顺序”暗示),你可以将索引传递给每个线程,并让它将结果写入数组中的“槽”。因此,所有线程都已完成处理(按任意顺序),结果将已正确排序,无需完全进行后处理排序。
答案 1 :(得分:1)
任务并行库现在是Reactive Extensions for .NET Framework的一部分,使得这样的事情变得微不足道。有一组用于并行化代码的Parallel
构造,以及一组可以与它们一起使用的线程安全Concurrent{Container}s
。
以下是使用Parallel.For
和ConcurrentBag
来存储结果的一组数字的示例。
using System.Threading.Tasks;
using System.Collections.Concurrent;
namespace ParallelTest
{
class Program
{
static void Main(string[] args)
{
var results = new ConcurrentBag<int>();
Parallel.For(0, 10, i =>
{
results.Add(i * i);
});
foreach (int i in results)
System.Console.WriteLine(i);
}
}
}
ConcurrentBag
是常规IEnumerable
,因为您可以看到我使用常规的非平行foreach
来打印结果。
注意:所有这些东西在.NET 4.0中实际上是标准的,如果你想要.NET 3.5,你只需要Rx。
答案 2 :(得分:1)
如果您使用的是.Net 4,则可以使用Task类。这是合并List
的示例Task<List<string>> task1 = new Task<List<string>>(SomeFunction);
Task<List<string>> task2 = new Task<List<string>>(SomeFunction);
task1.Start();
task2.Start();
var taskList = new List<Task<List<string>>> {task1, task2};
Task.WaitAll(taskList.ToArray());
List<string> res = new List<string>();
foreach (Task<List<string>> t in taskList)
{
res.AddRange(t.Result);
}
和你的功能
List<string> SomeFunction()
{
return new List<string>{"1","2"};
}
答案 3 :(得分:0)
在启动每个线程时,将其传递给序列标识符和回调方法,并递增一个指示正在运行的线程总数的计数器。当每个线程完成时,它会调用回调方法,该方法减少正在运行的线程数,并将结果插入SortedDictionary
,由序列ID键入。当最后一个线程完成时,回调可以指示您的主程序。