2016-03-14 366 views
2

我有一個異步代碼塊在頁面加載運行。 的代碼運行smoothy直到你到達那裏,我們創建一個新的task.On執行該代碼塊中的等待只是凍結,然後在控制犯規回來好像代碼capturevalue方法只是去死鎖異步等待導致死鎖

protected void Page_Load(object sender, EventArgs e) 
    { 
     try 
     { 
      var textvalue = GetTextValueFromTask(); 
      txtbox.Text = textvalue.Result; 
      string ss = ""; 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex.ToString()); 
     } 
    } 

    private async Task<string> GetTextValueFromTask() 
    { 
     string strReturn = await CaptureValue(); 
     return strReturn; 
    } 

    private async Task<string> CaptureValue() 
    { 
     Thread.Sleep(5000); 
     Task<string> T = Task.Factory.StartNew<string>(() => "hi"); 
     return await T; 
    } 

然後我在Capturevalue方法中做了一些小改動。

private async Task<string> CaptureValue() 
    { 
     Thread.Sleep(5000); 
     Task<string> T = Task.Factory.StartNew<string>(() => "hi"); 
     string ss = T.Result; 
     return await T; 
    } 

一旦我作出改變它開始工作normal.What差異並使其對剛剛獲取的結果開始。請幫助我Iam一個新手異步

+4

'Thread.Sleep'和等待任務的'Result'在異步代碼中是一個很大的禁忌,特別是當涉及到UI時。閱讀,摘要,行動:http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html – spender

+0

@spender你如何在評論中突出顯示單詞作爲代碼?謝謝 –

+0

@FirstStep:http:// stackoverflow。com/editing-help#註釋格式 – spender

回答

1

區別是第二次它不會發生任何「等待」,因爲你自己等待任務,所以await不會做任何事情。 我想你錯過了等待關鍵字的時候,在這裏:

var textvalue = await GetTextValueFromTask(); 

沒有它,你的方法GetTextValueFromTask運行同步,那麼就變成這樣await發生CaptureValue方法。但是await的默認行爲是它試圖捕獲它被調用的同步上下文,並在該上下文中繼續該方法的其餘部分,在您的示例中,它是WPF同步上下文,該上下文不允許執行多個線程立刻。但是繼續不能繼續,因爲上下文已經被等待機制使用。

所以,再來一次。有一個線程(UI線程),執行你的代碼,直至最後的await,這是return await T;,那麼它產生返回給調用者 - GetTextValueFromTask,並再次當它被封鎖的Page_Load,因爲一開始你叫GetTextValueFromTask同步(無需等待)。之後,您的操作T完成,並且您的代碼嘗試使用初始同步上下文(WPF之一)繼續執行。但它不能,因爲它已經在Page_Load中等待。

在評論中link更詳細地介紹了情況。

也可以考慮不使用異步Thread.Sleep /等待的情況,因爲它殺死的代碼的所有「異步」的性質。更多閱讀:link

不直接適用於您的源代碼的另一種常規建議是不使用Task.Factory.StartNew,而是使用Task.Run。解釋here

1

請使用Task.Run()代替Task.Factory.StartNew()

var T = Task.Run(() => "hi"); 

它是由Task.Run來決定如何處理這個任務。

也請在不要求繼續被在awaiter線程上下文做你的await調用使用.ConfigureAwait(假)。