异步等待性能 - 直接方法调用与任务包装器调用

Mri*_*boj 1 .net c# asynchronous task task-parallel-library

我创建的一个小程序,用于理解Async Await的工作并在for循环中调用async方法,作为直接方法调用:

sumProgram.CallSum(i, i + 1);
Run Code Online (Sandbox Code Playgroud)

或使用Task API Task.Run / Task.Factory.StartNew

我最初的理解是Task API会使它大大加快,但与我的期望相反,这肯定反映了我的理解不足,直接调用在性能方面要好得多.实际上,当在GetSum方法中引入额外的线程休眠时,它似乎只会影响任务调用,而且也会影响很大.

现在我理解直接调用的第一部分更快,因为它们是异步执行的,并且没有添加到任务列表并使它们等待的开销,但是当我将相同的技术转移到真正的编程范例时,那么问题遗迹:

  • 对于直接调用,没有什么可以模拟Task.WaitAll,所以他们会退出调用方法,即使所有执行都没有完成,所以我唯一的选择任务包装器.

  • 我得到了令人费解的结果,因为对于直接调用,秒表将在所有执行完成之前发布时间,并且由于waitAll,任务包装器不会出现这种情况.

  • 要执行此程序,您需要注释/取消注释相关部分以获得正确的结果

     class Program
        {
            static void Main(string[] args)
            {
                Program sumProgram = new Program();
    
            List<Task> taskList = new List<Task>(); // Only For Task
    
            Stopwatch sw = Stopwatch.StartNew();
    
            for (int i = 0; i < 100000; i++)
            {
                taskList.Add(Task.Factory.StartNew(() => { sumProgram.CallSum(i, i + 1); })); // For Task use one 
                taskList.Add(Task.Run(() => { sumProgram.CallSum(i, i + 1); })); // For Task use one 
                sumProgram.CallSum(i, i + 1);
            }
    
            Task.WaitAll(taskList.ToArray()); // Only For Task
    
            sw.Stop();
            Console.WriteLine("Time Elapsed :: " + sw.ElapsedMilliseconds);
        }
    
        public async Task CallSum(int num1, int num2)
        {
            Func<int> callFunc = (() =>
            {
                return GetSum(num1, num2);
            });
    
            int result = await Task.Run<int>(callFunc);
            //Console.WriteLine("Sum Result :: " + result);
        }
    
        public int GetSum(int num1, int num2)
        {
            Thread.Sleep(10);
            return (num1 + num2);
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

Ste*_*ary 5

async !="更快"

事实上,async代码几乎总是(略微)慢.

那么,为什么要使用async

在客户端(UI)应用程序上,async允许您保持对用户的响应.对比此代码:

void Button_Click()
{
  Thread.Sleep(10000);
}
Run Code Online (Sandbox Code Playgroud)

使用此代码:

async void Button_Click()
{
  await Task.Delay(10000);
}
Run Code Online (Sandbox Code Playgroud)

在服务器端(例如,ASP.NET),async允许您的代码使用更少的线程来提供更多请求.因此,提高了可扩展性.

请注意,在这两种情况下,async代码实际上都比同步代码.对于UI,睡眠当前线程比创建和启动计时器,创建和等待任务,然后在计时器触发时恢复异步方法更快.对于ASP.NET,阻塞当前线程比为异步操作创建任务更快,然后在异步方法恢复时将请求上下文切换到另一个线程.

但是,async带来其他好处.对于UI,在延迟期间不会阻止UI线程.对于ASP.NET,请求线程可以在异步操作正在进行时自由处理其他请求.

async不是速度; 它是关于释放当前线程.