我正在执行Web请求以获取消息,然后等待处理该消息,然后再次重复整个过程。
消息的处理将长时间运行,并且线程可能处于等待状态,可能允许在其他地方使用它。我想要的是继续while循环,获取更多消息并在线程空闲时处理它们。
当前同步代码:
while(!cancellationToken.IsCancelled) {
var message = await GetMessage();
await ProcessMessage(message); // I'll need it to continue from here if thread is released.
}
使用的场景是消息队列消费者服务。
答案 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