Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/259.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用wait Task.Delay来提高性能_C#_.net_Asynchronous_Async Await - Fatal编程技术网

C# 使用wait Task.Delay来提高性能

C# 使用wait Task.Delay来提高性能,c#,.net,asynchronous,async-await,C#,.net,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

假设我希望开始时每秒平均分配大约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);
    }
}

我试着用
numberOfCallsPerSecond=500运行它,大约需要10秒,我预计
Generate
大约需要1秒,而不是10倍以上我的心理调试器说你的
调用
方法有一个重要的同步部分(即
等待
之前的部分)同步执行需要时间

如果希望
Generate
方法仅“启动”这些
调用
调用并使它们同时运行(包括同步部分),则需要使用
任务将它们卸载到
线程池
线程。运行

var task = Task.Run(() => Call());
await Task.Delay(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);
    }
}
公共异步任务生成(int numberOfCallsPerSecond)
{
var appead=Stopwatch.StartNew();
var delay=TimeSpan.fromMiliconds(1000/numberOfCallsPerSecond);//调用应每1000/numberOfCallsPerSecond毫秒发生一次
for(int i=0;iexpectedI)等待任务,延迟(Delay);
}
}

如果将timespan与Task.Delay()一起使用,它将杀死CPU。使用一个整数,它不会。真实的故事。不知道为什么。

你能给调用方法一些代码吗?你确定这个方法在返回任务对象之前不需要花费时间吗?你在大约10秒内500次调用的新结果与调度程序quantum非常吻合。嗨,伙计们,请忘记Call()方法,检查我的编辑嘿,谢谢回答,你能检查我的编辑吗?问题的第一次修订提到了这一点“没有
Task.Delay
in place代码在3ms内完成”这似乎排除了这个解释嘿,很好的答案解释了这一点:)。我对开销感到非常惊讶。将尝试您的解决方案。+1
wait Task.Delay()
不会导致线程在给定时间内休眠。相反,它使用计时器,并在计时器过期时安排继续执行。因此,这里重要的是计时器的分辨率,而不是休眠的分辨率。虽然默认情况下两者都是16毫秒,这就是为什么观察到的行为与您描述的行为相同。@svick:我没有假设
Task.Delay()
使线程休眠。如果没有任务准备就绪,任务调度循环将停止。因此,如果我在自定义版本的
Delay()中使用更精确的计时器
,你会期望每个
等待
,都有相同的~16毫秒延迟?@svick:你是对的,实际上并不要求线程唤醒速度慢。但重要的是调度程序的数量,因为线程调度和计时器使用相同的硬件计时器中断。调度程序ISR使线程可运行,因为线程上的计时器已过期。使用您的“精确计时器”,未来将使线程可运行。您可以发布一些代码/基准测试吗?这将是一个很好的补充。当我找到时间时,我会尽量记住将一个放在一起。这是我去年某个时候在编写日志跟踪程序时发现的。
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);
    }
}