2017-07-28 247 views
4

这是我的实际代码:为什么不等待?

async Task getData() 
    { 
     Thread.Sleep(5000); 
     Console.WriteLine("Step 1"); 

     using (HttpClient api = new HttpClient()) 
      await api.GetAsync("http://google.com/").ContinueWith(
       (getTask) => 
        Console.WriteLine(getTask.Result.StatusCode); 
      ); 

     Console.WriteLine("Step 2"); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     Task<Task> task = new Task<Task>(getData); 
     task.Start(); 
     task.Wait(); 
     Console.WriteLine("Step 3"); 
    } 

我得到以下输出:

Step 1 
Step 3 
OK 
Step 2 

为什么Step 3不来Step 2后?

如何让它按顺序工作,即只返回到getData的调用者,直到getData中的所有内容完成为止?

+2

尝试'task.Result.Wait()',但你的例子似乎有点过于复杂。 –

+0

谢谢!有用。可以解释为什么?如何控制流程绕过getData方法的结尾返回给调用者? –

+3

看起来你应该真正阅读/通过正确的介绍异步/等待(例如[这个](https://blog.stephencleary.com/2012/02/async-and-await.html)例如) 。简而言之:'getData'已经返回一个任务,通过将它包装在另一个任务中,你必须等待内部任务。或者直接在'button1_Click'中写'await getData(...)'。但要小心,异步/等待还有更多 - 真正阅读更多内容。 –

回答

4

你也应该庆祝你的事件处理程序为async

private async Task button1_Click(object sender, EventArgs e) 

await代替Wait

private async Task button1_Click(object sender, EventArgs e) 
{ 
    await getData(); 

    Console.WriteLine("Step 3"); 
} 

当我们使用异步/ AWAIT模式,我们应该走这条路,直到第一方法启动它。否则,通过明确调用WaitResult,我们可能会遇到死锁问题。此外,显式调用这些方法可以阻止正在执行的线程。所以你放弃了使用async/await的主要好处,它不会阻塞正在执行的线程,并在一个单独的线程上运行一些代码,并且一旦完成,就会从停止的地方继续执行代码。

+0

谢谢。我不知道一个事件处理程序可以是'async'。这是否意味着所有调用事件处理程序的代码也是'async'? –

+0

@欢迎您。这意味着可以异步处理事件而不会阻止您的应用程序。例如,如果我们说WPF应用程序,并且按钮单击会触发网络调用,需要花费相当长的时间才能完成,那么如果相应的处理程序不是异步处理程序,则您的UI将冻结。 – Christos

2

要简单明了地尝试和放置东西 - async Task(和<T>)方法本身负责分配代表其完成的对象Task

如果你发现自己与async方法工作分配Task自己的对象(无论是直接,因为在这里,或者使用静态工厂方法,如Task.Run),你一定要认识到,不止一个Task对象现在存在。你必须小心,并认识到你创建Task的情况(如这里),他们自己现在返回Task s。

这是好得多,如果可能的话,拥抱async一路(如要修改的每个函数为async,你会那么容易找到每个调用点,使该位置async为好),并停止分配任何Task是你自己。

相关问题