我有单独处理'很多'(可能> 100,000)记录的C#要求。顺序运行此过程证明是非常慢的,每条记录需要大约一秒左右完成(超时错误设置为5秒)。
我想尝试使用一定数量的工作'线程'来异步运行这些任务(我谨慎地使用术语'thread',因为我不确定我是否应该查看线程,或任务或别的东西)。
我查看了ThreadPool
,但我无法想象它可以排队所需的请求量。我理想的伪代码看起来像这样......
public void ProcessRecords() {
SetMaxNumberOfThreads(20);
MyRecord rec;
while ((rec = GetNextRecord()) != null) {
var task = WaitForNextAvailableThreadFromPool(ProcessRecord(rec));
task.Start()
}
}
我还需要一种处理方法可以向父/调用类报告的机制。
任何人都可以通过一些示例代码向我指出正确的方向吗?
答案 0 :(得分:7)
一个可能的简单解决方案是使用TPL数据流块,这是对TPL的更高抽象,具有并行度等的配置。您只需创建块(在这种情况下为ActionBlock
),Post
所有内容,等待异步完成,TPL Dataflow将为您处理所有其余内容:
var block = new ActionBlock<MyRecord>(
rec => ProcessRecord(rec),
new ExecutionDataflowBlockOptions{MaxDegreeOfParallelism = 20});
MyRecord rec;
while ((rec = GetNextRecord()) != null)
{
block.Post(rec);
}
block.Complete();
await block.Completion
另一个好处是,只要第一条记录到达,块就会开始工作,而不仅仅是在收到所有记录后。
如果您需要报告每条记录,可以使用TransformBlock
进行实际处理,并将ActionBlock
链接到执行更新的地方:
var transform = new TransfromBlock<MyRecord, Report>(rec =>
{
ProcessRecord(rec);
return GenerateReport(rec);
}, new ExecutionDataflowBlockOptions{MaxDegreeOfParallelism = 20});
var reporter = new ActionBlock<Report>(report =>
{
RaiseEvent(report) // Or any other mechanism...
});
transform.LinkTo(reporter, new DataflowLinkOptions { PropagateCompletion = true });
MyRecord rec;
while ((rec = GetNextRecord()) != null)
{
transform.Post(rec);
}
transform.Complete();
await transform.Completion
答案 1 :(得分:1)
您是否考虑过使用动作进行并行处理? 即,创建一个处理单个记录的方法,将每个记录方法作为动作添加到列表中,然后在列表上执行parrallel.for。
Dim list As New List(Of Action)
list.Add(New Action(Sub() MyMethod(myParameter)))
Parallel.ForEach(list, Sub(t) t.Invoke())
这是在vb.net中,但我认为你得到了主旨。