Dan*_*inu 5 .net c# asynchronous async-await
假设我想开始大致每秒分配N个任务.
所以我尝试了这个:
public async Task Generate(int numberOfCallsPerSecond)
{
var delay = TimeSpan.FromMiliseconds(1000/numberOfCallsPerSecond); // a call should happen every 1000 / numberOfCallsPerSecond miliseconds
for (int i=0; i < numberOfcallsPerSecond; i++)
{
Task t = Call(); // don't wait for result here
await Task.Delay(delay);
}
}
Run Code Online (Sandbox Code Playgroud)
起初我预计这将在1秒内运行,但是numberOfCallsPerSecond = 100它需要16 seconds我的12核CPU.似乎等待Task.Delay增加了很多开销(当然没有它就可以在3ms内生成调用.
我没想到await会在这种情况下增加很多开销.这是正常的吗?
编辑:
请忘记Call().运行此代码显示类似的结果:
public async Task Generate(int numberOfCallsPerSecond)
{
var delay = TimeSpan.FromMiliseconds(1000/numberOfCallsPerSecond); // a call should happen every 1000 / numberOfCallsPerSecond miliseconds
for (int i=0; i < numberOfcallsPerSecond; i++)
{
await Task.Delay(delay);
}
}
Run Code Online (Sandbox Code Playgroud)
我试着用numberOfCallsPerSecond = 500它运行它需要大约10秒,我预计Generate大约需要1秒,而不是10倍
Ben*_*igt 16
Task.Delay重量轻但不准确.由于没有延迟的循环完成得更快,听起来你的线程正在空闲并使用操作系统休眠等待计时器过去.根据OS线程调度量程(在执行线程抢占的同一中断处理程序中)检查定时器,默认为16ms.
你可以减少量子timeBeginPeriod,但是如果你需要速率限制而不是精确的定时更好(更节能)的方法是跟踪经过的时间(Stopwatch类是好的)和调用的数量,并且只在拨打电话已经赶上了经过的时间.总体效果是你的线程每秒会被唤醒~60次,并且每次都会启动一些工作项.如果您的CPU忙于其他事情,那么当您获得控制权时,您将启动额外的工作项目 - 尽管如果这是您需要的,那么同时启动项目的数量也非常简单.
public async Task Generate(int numberOfCallsPerSecond)
{
var elapsed = Stopwatch.StartNew();
var delay = TimeSpan.FromMiliseconds(1000/numberOfCallsPerSecond); // a call should happen every 1000 / numberOfCallsPerSecond miliseconds
for (int i=0; i < numberOfcallsPerSecond; i++)
{
Call(); // don't wait for result here
int expectedI = elapsed.Elapsed.TotalSeconds * numberOfCallsPerSecond;
if (i > expectedI) await Task.Delay(delay);
}
}
Run Code Online (Sandbox Code Playgroud)