睡眠真的会阻止执行吗?

问题描述 投票:0回答:1

几乎所有关于C#异步编程的介绍都警告不要使用Sleep指令,因为它会阻塞整个线程。

但我发现在睡眠期间,正在获取和执行队列中的任务。看到:

    using System;
    using System.Threading.Tasks;

    namespace TestApp {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("Main");
                Program.step1();

                for (int i = 0; i < 6; i++) {
                    System.Threading.Thread.Sleep(200);
                    Console.WriteLine("Sleep-Loop");
                }
            }

            private static async void step1() {
                await Task.Delay(400);
                Console.WriteLine("Step1");
                Program.step2();
            }

            private static async void step2() {
                await Task.Delay(400);
                Console.WriteLine("Step2");
            }
        }
    }

输出:

    Main
    Sleep-Loop
    Sleep-Loop
    Step1
    Sleep-Loop
    Sleep-Loop
    Step2
    Sleep-Loop
    Sleep-Loop

我的问题:

  1. Sleep是否真的允许排队的任务执行,或者其他什么事情发生?
  2. 如果是,那么在其他所有闲置情况下是否也会发生这种情况?例如在投票期间?
  3. 在上面的示例中,如果我们注释掉循环,那么应用程序将在任何任务执行之前退出。还有另一种方法可以预防吗?
c# .net asynchronous mono
1个回答
2
投票

在C#7.3中,您可以使用异步入口点,我建议使用它。

一些说明:

  1. 不要使用异步void,它对处理错误的方式有微妙之处,如果你看到自己写的异步无效,那就想想你在做什么。如果它不是一个事件处理程序,你可能做错了什么
  2. 如果您想等待一堆任务完成,请使用Task.WhenAll

修改的例子

static async Task Main(string[] args)
{
   Console.WriteLine("Start Task");
   var task = Program.step1();

   for (int i = 0; i < 6; i++)
   {
      await Task.Delay(100);
      Console.WriteLine("Sleep-Loop");
   }

   Console.WriteLine("waiting for the task to finish");
   await task;
   Console.WriteLine("finished");
   Console.ReadKey();
}

private static async Task step1()
{
   await Task.Delay(1000);
   Console.WriteLine("Step1");
   await Program.step2();
}

private static async Task step2()
{
   await Task.Delay(1000);
   Console.WriteLine("Step2");
}

重要的是要注意任务不是线程和async不平行,但它们可以。

如果您使用异步等待模式,则10次中有9次是IO绑定工作使用操作系统IO完成端口,因此您可以释放线程。它具有scalabilty和ui响应功能。

如果你没有做任何IO工作,那么实际上根本不需要async await模式,因此cpu工作应该只是在调用点时用Task.Run包装。没有用async方法包裹。

此时,还要注意使用任务不是异步和等待模式。虽然它们都有共同的任务,但它们并不是一回事。

最后;如果您发现需要使用异步代码并且忘记方式,请仔细考虑如何处理任何错误。

以下是一些指导原则。

  • 如果要进行IO工作,请使用async await模式。
  • 如果要进行CPU工作,请使用Task.Run。
  • 除非它用于事件处理程序,否则永远不要使用async void。
  • 永远不要在异步方法中包装CPU,让调用者使用Task.Run
  • 如果你需要等待任务,await它,永远不要调用Result,或Wait或使用Task.WhenAll
© www.soinside.com 2019 - 2024. All rights reserved.