多线程可能长时间运行的操作

时间:2016-06-13 15:08:48

标签: c# multithreading

我正在写一个Windows服务。我有一个必须由服务处理的记录的'backlog'(在SQL中)。积压也可能是空的。记录处理可能是一个非常长时间运行的操作(3分钟以上)。

我有一个类和方法,如果有任何要处理的记录,它将转到SQL,选择一个记录并处理它。然后该方法将存在,就是这样。注意:我事先无法知道将处理哪些记录 - 类方法将此作为其逻辑的一部分。

我想实现并行处理。我希望随时拥有X个工作人员(其中X是主机PC的最佳选择)。虽然积压工作是空的,但这些工人完成工作并很快退出(约50-100毫秒)。我希望任何“自由”工人重新开始(即重新开始)。

我已经做了一些阅读,并且我推断出ThreadPool对于长时间运行的操作来说不是一个好的选择。 .net 4.0+并行库也不是一个好选择,因为我不想等待所有工作者完成,我不想提前预定义/声明任务。

通俗地说,我想让X工作人员查询数据源以查找项目,当其中一些人发现这些项目时 - 对其进行操作,其余人员将继续寻找新推送的项目进入待办事项。

最好的方法是什么?我想我必须完全自己管理线程?即第一步 - 确定最佳线程数(可能通过检查Environment.ProcessorCount)然后启动X线程。在每个线程上监视IsAlive并重新启动它?这看起来非常不专业。

有什么建议吗?

3 个答案:

答案 0 :(得分:1)

您可以为每个核心启动一个任务,因为任务完成后会启动新任务。您可以根据ProcessorCount或特定数量使用numOfThreads

int numOfThreads = System.Environment.ProcessorCount;
// int numOfThreads = X;
for(int i =0; i< numOfThreads; i++)
task.Add(Task.Factory.StartNew(()=> {});
while(task.count>0) //wait for task to finish
{
      int index = Task.WaitAny(tasks.ToArray());
      tasks.RemoveAt(index);
      if(incomplete work)
      task.Add(Task.Factory.StartNew()=> {....});
}

var options = new ParallelOptions();
options.MaxDegreeOfParllelism = System.Environment.ProcessorCount;
Parallel.For(0,N,options, (i) => {/*long running computattion*/};

您可以使用BlockingCollection实现Producer-Coustomer模式

Dr.Joe Hummel在他的Pluralsight课程&#34;异步和并行编程:应用程序设计&#34;

上非常好地讲授了这个主题

答案 1 :(得分:0)

考虑使用TPL.DataFlow库中的ActionBlock<T>。它可以配置为使用所有可用的CPU核心同时处理多个消息。

ActionBlock<QueueItem> _processor;
Task _completionTask;
bool _done;

async Task ReadQueueAsync(int pollingInterval)
{
     while (!_done)
     { 
         // Get a list of items to process from SQL database
        var list = ...;

        // Schedule the work 
        foreach(var item in list) 
        {
          _processor.Post(item);
        }

       // Give SQL server time to re-fill the queue
       await Task.Delay(pollingInterval);
     }

     // Signal the processor that we are done
     _processor.Complete();

}

void ProcessItem(QueueItem item)
{
      // Do your work here
} 

void Setup()
{
      // Configure action block to process items concurrently
      //  using all available CPU cores
     _processor= new ActionBlock<QueueItem>(new Action<QueueItem>(ProcessItem), 
         new    ExecutionDataFlowBlock{MaxDegreeOfParallelism =  DataFlowBlockOptions.Unbounded});
    _done = false;

    var queueReaderTask = ReadQueueAsync(QUEUE_POLL_INTERVAL);
    _completionTask = Task.WhenAll(queueReaderTask, _processor.Completion);   
}


void Complete()
{
    _done = true;
    _completionTask.Wait();
}

答案 2 :(得分:-1)

为什么不直接将要运行的项目或任务列表交给任务并行库,让框架处理处理器数量?

List<InfoObject> infoList = GetInfo();
ConcurrentBag<ResultObject> output = new ConcurrentBag<ResultObject>();

await Task.Run(() =>
{
    Parallel.Foreach<InfoObject>(infoList, (item) =>
    {
        ResultObject result = ProcessInfo(item);
        output.Add(result);
    });
});

foreach(var resultObj in output)
{
    ReportOnResultObject(resultObj);
}

List<InfoObject> infoList = GetInfo();
List<Task<ResultObject>> tasks = new List<Task<ResultObject>>();

foreach (var item in infoList)
{
    tasks.Add(Task.Run(() => ProcessInfo(item)));
}

var results = await Task.WhenAll(tasks);

foreach(var resultObj in results)
{
    ReportOnResultObject(resultObj);
}

H/T 到 IAmTimCorey 教程:

https://www.youtube.com/watch?v=2moh18sh5p4

https://www.youtube.com/watch?v=ZTKGRJy5P2M

相关问题