如何使用线程处理许多任务

时间:2015-01-08 13:55:43

标签: c# .net multithreading task-parallel-library

我有单独处理'很多'(可能> 100,000)记录的C#要求。顺序运行此过程证明是非常慢的,每条记录需要大约一秒左右完成(超时错误设置为5秒)。

我想尝试使用一定数量的工作'线程'来异步运行这些任务(我谨慎地使用术语'thread',因为我不确定我是否应该查看线程,或任务或别的东西)。

我查看了ThreadPool,但我无法想象它可以排队所需的请求量。我理想的伪代码看起来像这样......

public void ProcessRecords() {
    SetMaxNumberOfThreads(20);
    MyRecord rec;
    while ((rec = GetNextRecord()) != null) {
        var task = WaitForNextAvailableThreadFromPool(ProcessRecord(rec));
        task.Start()
    }
}

我还需要一种处理方法可以向父/调用类报告的机制。

任何人都可以通过一些示例代码向我指出正确的方向吗?

2 个答案:

答案 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中,但我认为你得到了主旨。