【发布时间】:2013-12-31 13:26:17
【问题描述】:
在使用 .Net 4.0/4.5 任务时,如何实现有效的速率限制算法(每个时间间隔执行 N 次特定操作)?例如,如果在一秒钟内发送的消息超过 N 条,我希望 SendMessageAsync 阻止(不发送另一条消息)。
await Task.WhenAll(
Enumerable.Range(0, TOTAL_MESSAGES)
.Select(async x =>
{
await clientSession.SendMessageAsync(CreateMessage());
}));
我尝试在SendMessageAsync 中使用Task.Delay,但由于等待Task.Delay 立即返回,所以下一条消息将在没有任何阻塞的情况下发送。
public async Task<ResponseMessage> SendMessageAsync(RequestMessage message)
{
int sleepTime;
if (throttler.ShouldThrottle(out sleepTime))
{
await Task.Delay(sleepTime);
}
return await InternalMessageWithoutWaitingAsync(message);
}
我可以将 await Task.Delay(sleepTime) 更改为 Thread.Sleep(sleepTime) 从而在异步之前等待,但我想知道在使用任务时这是否是一个好习惯。
【问题讨论】:
-
我只会在“节流器”发出“开始”信号时开始下一个任务。我认为这比开始所有任务并立即等待大多数任务更好。
-
基于时间的操作,如限制在一个时间间隔内最好使用Rx而不是直接使用
async。 -
@RobertMircea 使用
Thread.Sleep绝对是一种不好的做法(浪费资源)。我没有得到您对next message will be sent without any blocking的关注。这是否意味着您需要按顺序执行所有任务?如果你的场景真的很复杂,你可以看看实现你自己的TaskScheduler:How to: Create a Task Scheduler That Limits Concurrency -
@outcoldman 正如@StephenCleary 所提到的,问题是关于时间间隔的节流,而不是限制某个时刻的并行操作(并发)的数量。
next message will be sent without any blocking表示在不考虑我试图达到的 1 秒间隔内的速率限制的情况下发送下一条消息。 -
@RobertMircea 然后你可以实现你自己的
TaskScheduler(如果你不想使用Rx)
标签: c# asynchronous async-await c#-5.0