2017-05-19 51 views
-2

任何人都可以向我解释为什么第二个Working!Done之后显示?异步/等待执行步骤

Stating 
Doing Work 
Working! 
Done 
Working! 
Work completed 

第二个问题,为什么我就不能做到像下面让任务结果:

Task result = await LongOperation(); 

而最后一个问题是什么是代表与AWAIT /异步例如使用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); 
    } 
} 
+1

1.因为你调用了'LongOperation'两次2.因为这不是'await'的工作方式3.异步调用一个同步操作(将来请尽量保持它不变每个帖子有一个问题) –

+3

请参阅[如何提问](http://stackoverflow.com/help/how-to-ask)。你应该避免在同一个线程中询问多个问题,并且它会使它成为一个我们很容易理解你是否提供了一些你所问的内容(特别是在你的问题中)第一个问题)的意思。 – stybl

回答

0

这是因为你已经宣布DoWork()异步的void返回类型。这使得它成为异步运行的“火灾和遗忘”方法。如果您有DoWork()返回Task而不是void,那么您可以await它,这将确保您的“完成”消息将在DoWork()完成执行后发生。

此外,await解开任务结果,所以你不能等待它,并在同一时间得到的价值。如果您想直接使用Task结果,请不要await它。

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

0

有理由“完成!”看起来早于你的预期是因为你的不是awaitworker.DoWork();(和DoWork需要返回Task能够使用await)。那么DoWork()会立即返回执行延迟到另一个线程,并立即去到控制台写入“完成”的下一行。

关于Task result = await LongOperation();await发生在作为参数awaitable对象(即Task),检测代表你其.Result属性,提取结果并将其返回。因此,您要么删除await以获取任务实例,要么您将await等待任务完成并提取呼叫的实际返回值。

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

+0

你不能'等待'一个void返回类型。 – Technetium

+0

好点,修改我的答案。 – LB2

+0

尽量避免无效的语法没有控制任务火灾,忘记 –

0
  1. Working显示Done!后,因为在你static void Main你是不是在等待worker.DoWork();完成,所以程序执行的下一行。你应该改变DoWork方法是这样的:

    public async Task DoWork() 
    { 
        // 
    } 
    

并改变这样调用它:

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

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

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

    +0

    CPU绑定方法是主动使用的方式 –

    0

    考虑您的问题一个接一个:

    1. Main,你不等待DoWork。这意味着它被调用,然后继续执行Main中的代码,而不用等待DoWork完成。因此,在第二个“工作”之前立即将“完成”打印到控制台。
    2. 这不是await关键字的作用。从documentation

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

    实际上,为了await的方法,它必须有返回类型Task<T>,其中T是实际的类型是什么,你return在你的代码。你的方法LongOperation实际上并没有在这个例子中返回任何东西。

    1. Task.Run用于运行任何方法或代码块作为任务。它可以被解雇和忘记(Task.Run([something];),或等待任何其他任务(await Task.Run([something]);。请参阅它的文档here,虽然我不知道它会有很大的帮助,用户Stephen Cleary解释得很好,在this答案,以及一些其他相关信息