异步/等待执行步骤

时间:2017-05-19 22:11:38

标签: c#

有人可以向我解释为什么在Working!之后显示第二个Done

Stating
Doing Work
Working!
Done
Working!
Work completed

第二个问题为什么我不能像下面那样得到任务结果:

Task result = await LongOperation();

最后一个问题是在我的代码中代表await / async使用Task.Run的原因是什么?它可以在哪里使用,还是不好用?

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Starting");
        var worker = new Worker();
        worker.DoWork();
        Console.WriteLine("Done");
        Console.ReadKey();
    }
}

public class Worker
{
    public async void DoWork()
    {
        Console.WriteLine("Doing work");

        await LongOperation();
        await LongOperation();

        Console.WriteLine("Work completed");
    }

    private async Task LongOperation()
    {
        Console.WriteLine("Working!");
        await Task.Delay(200);
    }
}

4 个答案:

答案 0 :(得分:0)

这是因为您已声明DoWork()异步,返回类型为void。这使得它成为了一场“火上浇油”而又“忘掉了”。异步运行的方法。如果您DoWork()返回Task而不是void,则可以await它,这样可以确保您完成"完成" DoWork()完成执行后会发生消息。

此外,await会解包任务结果,因此您无法等待它并同时获取该值。如果您希望直接使用Task结果,请不要await

您指定的代码中没有特定区域,您应该使用Task.Run()

答案 1 :(得分:0)

有理由"完成!"出现的时间比您预期的要早,因为您在await前面 worker.DoWork();DoWork需要返回Task才能使用await)。所以会发生什么,DoWork()会立即返回执行延迟到另一个线程,并立即转到下一行,即控制台写入"完成"。

关于Task result = await LongOperation();await接受参数等待对象(即Task),代表您检查其.Result属性,提取结果并将其返回。因此,您可以删除await以获取任务实例,也可以将await置于等待任务完成并提取调用的实际返回值。

使用Task.Run或通过任务工厂有几个原因,一个例子是传递lambda函数来执行(可能带有闭包)。我会参考TPL上的MSDN库进行详细的潜水。

答案 2 :(得分:0)

  1. Working会在Done!之后显示,因为在您的static void Main中,您还没有等待worker.DoWork();完成,因此程序会执行下一行。您应该像这样更改DoWork方法:

    public async Task DoWork()
    {
        //
    }
    
  2. 并将调用更改为:

    worker.DoWork().GetAwaiter().GetResult();
    
    1. 您不能,因为使用await您的LongOperation将不会返回Task。例如,如果您有这样的签名,当您使用await时,您需要打开结果:

      public Task<int> GiveANumberAsync()
      {
          return Task.FromResult(12);
      }
      
      int result = await GiveANumberAsync();
      
    2. 对于这个问题,我认为我不能比斯蒂芬in this answer更好地解释,他说:

    3.   

      使用Task.Run调用CPU绑定方法。

答案 3 :(得分:0)

逐一提问:

  1. Main中,您不等待DoWork。这意味着它被调用,然后Main中的代码继续执行,而不等待DoWork完成。因此,&#34;完成&#34;在第二个&#34; Working&#34;。
  2. 之前立即打印到控制台
  3. 这不是await关键字的作用。来自documentation
  4.   

    await运算符应用于异步方法中的任务,以暂停方法的执行,直到等待的任务完成。该任务代表了正在进行的工[...]   应用await运算符的任务通常是调用实现基于任务的异步模式的方法的返回值。示例包括TaskTask<TResult>类型的值。

    实际上,为了await方法,它必须具有返回类型Task<T>,其中T是代码中return的实际类型。您的方法LongOperation实际上并没有在此示例中返回任何内容。

    1. Task.Run用于将任何方法或代码块作为任务运行。它可以被解雇和忘记(Task.Run([something];),或等待任何其他任务(await Task.Run([something]);。请参阅它的文档here,虽然我不确定它会是多少用户Stephen Clearythis回答中解释了这一点以及其他一些相关信息。