2017-05-19 47 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答案,以及一些其他相關信息