线程在等待时继续处理

时间:2017-09-24 05:18:57

标签: c# multithreading task

我正在执行Web请求以获取消息,然后等待处理该消息,然后再次重复整个过程。

消息的处理将长时间运行,并且线程可能处于等待状态,可能允许在其他地方使用它。我想要的是继续while循环,获取更多消息并在线程空闲时处理它们。

当前同步代码:

while(!cancellationToken.IsCancelled) {
  var message = await GetMessage();

  await ProcessMessage(message); // I'll need it to continue from here if thread is released.
}

使用的场景是消息队列消费者服务。

2 个答案:

答案 0 :(得分:2)

考虑到使用async / await,您当前的代码不一定是synchronous(在线程术语中 - 可以在不同的线程上调用continuation),尽管之间的依赖关系显然必须坚持收到信息并加以处理。

  
    

Re:线程可能处于等待状态,可能允许在其他地方使用

  

等待编码良好的I / O绑定工作根本不需要使用线程 - 请参阅Stephen Cleary's There is no thread。假设两个等待的任务是IO绑定的,那么在等待IO绑定工作时,您的代码可能根本不会消耗任何线程,即您的应用程序的其余部分将使用Threadpool。因此,如果你唯一关心的是浪费线程,那么就不需要了。

但是,如果您关注的是性能和额外的吞吐量,如果有下行容量来执行ProcessMessage的并发调用(例如,多个下游Web服务器或其他数据库容量),那么您可以查看并行化IO绑定工作(再次,不需要更多的Threadpool线程)

例如,如果您能够重新编写GetMessages调用以一次检索批次,则可以尝试:

var messages = await GetMessages(10);
var processTasks = messages
    .Select(message => ProcessMessage(message));
await Task.WhenAll(processTasks);

(如果您无法触摸代码,则可以循环GetMessages以在Task.WhenAll之前检索10条单独的消息

但是,如果您没有任何进一步的容量来进行并发ProcessMessage调用,那么您应该考虑解决瓶颈问题 - 例如添加更多服务器,优化代码或并行化ProcessMessage工作中完成的工作等。

理由是,如您所说,GetMessages从队列中检索数据。如果您没有能力处理您检索到的消息,那么您所能做的就是将消息排队到其他地方,这似乎毫无意义 - 而是将消息留在队列中,直到您准备好处理它们为止。队列深度还将创建可以监控的工作积压的可见性。

编辑,回复:偶尔一次ProcessMessage()通话需要的时间比其他人短得多

根据评论,OP提供了额外的信息,即偶尔的ProcessMessage通话需要比其他通话更长的时间,并且希望在此期间继续处理其他消息。

一种方法可能是使用此clever pattern here对Parallel任务应用超时,如果达到,将使任何长时间运行的ProcessTasks保持运行,并将继续下一批消息。

以下是有潜在危险的,因为它需要仔细平衡超时(1000毫秒以下)与观察到的行为不当ProcessMessage的频率 - 如果超时时间与“慢”的频率相比太低ProcessMessages,下游资源可能会不堪重负。

更安全(但更复杂)的补充是通过Task.IsCompleted跟踪不完整ProcessMessage任务的并发数量,如果达到阈值,则等待完成足够的这些任务将积压工作带到安全的水平。

while(!cancellationToken.IsCancelled) 
{
   // Ideally, the async operations should all accept cancellationTokens too
   var message = await GetMessages(10, cancellationToken);
   var processTasks = messages
      .Select(message => ProcessMessage(message, cancellationToken));
   await Task.WhenAny(Task.WhenAll(processTasks), 
                      Task.Delay(1000, cancellationToken));
 }

回复:对下游负载的安全水平进行限制 - TPL DataFlow更多可能会在这里使用。

答案 1 :(得分:0)

看看https://msdn.microsoft.com/library/hh191443(vs.110).aspx应该让你去。此外,似乎ProcessMessage以#As}' Async'结束。根据C#/ .NET样式指南。

您需要设置Task<ReturnTypeOfProcessMessage> procMessageTask = ProcessMessageAsync(message);

那么你可以在跑步的同时做生意, SomeBusiness(...)

然后

await procMessageTask;

好像你可能也想要某种类型的await-with-timeout功能,以便你可以进行民意调查,这里有一个与之相关的问题:

Asynchronously wait for Task<T> to complete with timeout

HTH