2016-07-11 46 views
2

我试图抓住异步等待模式。继this例如,我实现了 这个小程序:async等待错误的执行顺序

private async void asynchWork() 
{ 
    // Line 1 
    Task<string> readTask = asynchAwaitWork(); 

    // Line 2 
    synchWork(); 

    // Line 3 
    string result = await readTask; 

    // Line 4 
    Debug.WriteLine(result); 
    Debug.WriteLine("The End"); 
} 
private void synchWork() 
{ 
    for (int i = 0; i < 5; i++) 
    { 
     Debug.WriteLine("SynchWork For i : " + i); 
     Thread.Sleep(750); 
    } 
} 

private async Task<string> asynchAwaitWork() 
{ 
    for (int i = 0; i < 15; i++) 
    { 
     Debug.WriteLine("A-SynchWork For i : " + (i+111)); 
     Thread.Sleep(750); 
    } 

    return "finished"; 
} 

我预计,1号线执行,那么2号线和4号线将不得不等待,直到3号线完成并返回一个字符串。 但看着输出synchWork方法在asynchWork方法后执行。

A-SynchWork对于i:111

A-SynchWork对于i:112

A-SynchWork对于i:113

A-SynchWork对于i:114

A-SynchWork For I:115

...

A-SynchWork对于i:125

SynchWork对于i:0

SynchWork对于i:1个

SynchWork对于i:2

SynchWork对于i:3

SynchWork对于i:4

已完成

终结

我预期当asynchWork方法是buisy并等待在第3行的结果被在时所执行的方法synchWork。 这个例子中我误解了什么?还是仅仅是Debug.WriteLine的输出是按顺序执行的,但是真正的工作顺序是按照我的期望执行的?

编辑: 随着意见和答案的帮助下,我了解到:

  • 不要忽视警告,并研究它们的含义;使用await关键字允许等待)

  • 由该方法内部创建的Task执行的操作的结果。

编辑2:

  • 但任务必须启动!否则将不会有并行处理,编译器将通过主线程追踪它,而Line 3实际上只有Line 4的阻塞函数不多。

因为Thread.Sleep(750)只是一个模拟的工作,我并不真的需要Delay这也适用:

private async Task<string> asynchAwaitWork() 
{ 
    await Task.Run(()=> { 
     for (int i = 0; i < 15; i++) 
      { 
       Debug.WriteLine("A-SynchWork For i : " + (i+111)); 
       Thread.Sleep(750); 
      } 
      }); 
    return "finished";    
} 

非常感谢你。我学到了很多:)

+3

你应该得到'asynchAwaitWork'的编译器警告,它给出了为什么它不起作用的线索 –

+0

@ScottChamberlain等待丢失它说。因此它将被同步执行。我只是不太明白为什么从这个小小的信息。 –

+3

@MongZhu然后对这个警告做一些研究。这里有很多信息。 – Servy

回答

2

展望:

当3号线已执行,保证您的任务你有在1号线有完成执行不管是里面。

在第2行,您不能保证任务已开始执行或已完成。你不知道它是否会平行运行。你所知道的是有一个任务可以被安排执行。

在函数​​中创建的任务的实现是完全同步的。当实现细节返回将最终(在这种情况下是立即)的任务时返回一个字符串时,该实现细节将导致它完全完成打印内容。

请注意,您创建的任务不会打印任何内容。在当前实施中打印您的“A-SynchWork For i”消息是创建您的任务的副作用。

+0

很好的解释!所以这意味着在'asynchAwaitWork'部分:'异步任务'导致创建任务,但它永远不会并行运行,因为没有一行代码表示“开始(...)”或“润(...)'。这就是为什么它也不会打印任何东西?=!当'asynchAwaitWork'到达返回语句时,它将返回值赋给第3行传递给'result'的任务。 你答案的最后部分真的很有启发性! –

+0

更多的讨论可能对聊天格式更好。但是你的'asynchAwaitWork'和'console.WriteLine(“这是一个副作用”)相当。返回Task.FromResult(“完成”)。等待该任务与之前的WriteLine无关。 – Martijn

1

只需更换 Thread.Sleep(750);await Task.Delay(750);在asynchAwaitWork 的事情是,asynchAwaitWork开始在主线程工作。异常的工作 - 这是为了延续。使用await关键字,您创建延续,这就是为什么它开始并行工作。 还要将当前线程ID添加到输出中以查看发生了什么。例如:

private async void asynchWork() 
{ 
    // Line 1 
    Task<string> readTask = asynchAwaitWork(); 

    // Line 2 
    synchWork(); 

    // Line 3 
    string result = await readTask; 

    // Line 4 
    Debug.WriteLine(result); 
    Debug.WriteLine("The End"); 
} 
private void synchWork() 
{ 
    for (int i = 0; i < 5; i++) 
    { 
     Debug.WriteLine("SynchWork For i : " + i + " and thareadId = " + Thread.CurrentThread.ManagedThreadId); 
     Thread.Sleep(750); 
    } 
} 

private async Task<string> asynchAwaitWork() 
{ 
    for (int i = 0; i < 15; i++) 
    { 
     Debug.WriteLine("A-SynchWork For i : " + (i + 111) + " and thareadId = " + Thread.CurrentThread.ManagedThreadId); 
     await Task.Delay(750); 
     //Thread.Sleep(750); 
    } 

    return "finished"; 
} 

正如人们注意到的那样,Task.Delay(750)将使用相同的同步上下文(如果创建的话)。 个例子,假如你是从WPF

[STAThread] 
void Main() 
{ 
    var window = new Window(); 
    window.Loaded += (s, e) => { 
     asynchWork(); 
    }; 
    window.ShowDialog(); 
} 

运行的代码,你会看到所有发生在同一个线程。 因此,请注意,您可以使用await Task.Delay(750).ConfigureAwait(false);来避免这种情况。只有在你的主程序

+0

如果这是在控制台应用程序中运行,它们将并行运行,但如果在设置了“SyncronisationContext.Current”的情况下运行它,它将运行第一个“asynchAwaitWork”,然后是所有的“synchWork”,然后是其余的'asynchAwaitWork'。你需要做'等待Task.Delay(750).ConfigureAwait(false);'或者做任务 readTask = Task.Run(()=> asynchAwaitWork());' –

+0

yep,Task.Delay(750)继续当前的情况。因此,如果我们在U​​I线程中的WPF应用程序(例如)中运行它,则将在UI线程中运行延续。谢谢@ScottChamberlain,你是对的。 – tym32167

+0

@ tym32167“使用await关键字创建延续”为什么?你能详细说明一下吗? –