2016-11-23 76 views
5

我有一個方法返回一個對象的列表<>。此方法需要一段時間才能運行。列表<MyObject>不包含GetAwaiter的定義

private List<MyObject> GetBigList() 
{ 
    ... slow stuff 
} 

該方法從4或5個來源中調用。所以,我想我會嘗試使用異步並等待在這個列表生成時繼續移動。我加入這個方法:

public async Task<List<MyObject>> GetBigListAsync() 
{ 
    var resultsTask = GetBigList(); 
    var resuls = await resultsTask; 
    return resuls; 
} 

但是,在這條線:

var resuls = await resultsTask; 

我得到這個錯誤:

List<MyObject> does not contain a definition for GetAwaiter, and no extension method 'GetAwaiter' accepting a first argument of type List<MyObject> could be found.

我缺少什麼?

+1

你的示例代碼沒有顯示出任何使用任務的GetBigList方法也不會標記爲async,這意味着不能等待該方法的結果。 –

+0

嘗試異步任務<列表> GetBigList() – Mate

+2

請記住,await不會將異步操作轉換爲異步操作。等待將當前方法的其餘部分註冊爲*已有的*異步操作的繼續。等待是關於*管理異步*,而不是*創建*。如果你希望同步操作是異步的,你將不得不找出一種方法來實現這一點。 –

回答

9

resultTask只是從GetBigList()返回的列表,所以在那裏沒有任何異步發生。

你可以做的是通過使用Task.Run卸載任務的線程池一個單獨的線程,並返回awaitable Task對象:

// Bad code 
public Task<List<MyObject>> GetBigListAsync() 
{ 
    return Task.Run(() => GetBigList()); 
} 

雖然上面的例子最符合你正在嘗試做的,它是不是最佳實踐。嘗試使GetBigList()本質上是異步的,或者如果真的沒有辦法,就把執行代碼的決定放在一個單獨的線程上調用調用代碼,而不要將它隱藏在實現F.e中。如果調用代碼已經運行異步,沒有理由產生另一個線程。 This article更詳細地描述了這一點。

5

看來你是aysnc-await的新手。真正幫助我理解什麼是異步等待的是Eric Lippert在this interview.中給出的餐廳類比在中間的某處尋找異步等待。

在這裏他描述瞭如果一個廚師必須等待某件事情,而不是無所事事,他會開始環顧四周,看看他是否可以在此期間做其他事情。

異步等待類似。而不是等待要讀取的文件,要返回的數據庫查詢,要下載的網頁,您的線程將上傳調用堆棧以查看是否有任何調用者不在等待,並執行這些語句直到他看到等待。一旦他看到await線程再次調用堆棧,看看其中一個調用者是否正在等待。等一段時間,當文件被讀取,或者查詢完成等等時,執行await後面的語句。

通常在閱讀你的大名單時,你的線程會非常忙,而不是閒着等。不確定訂購另一個線程來完成這些工作會改善閱讀您的列表所需的時間。考慮測量兩種方法。

One reason to use async-await, even if it would lengthen the time needed to read the big list, would be to keep the caller (user interface?) responsive.

爲了讓你的函數異步,你應該做到以下幾點:

  • 聲明函數異步
  • 代替TResult回報Tast<TResult>和替代void回報Task
  • 如果你的函數調用其他異步功能,請考慮記住返回的任務,而不是await,做其他有用的事情,你需要做的和await當你需要結果時的任務。
  • 如果你真的想讓另一個線程做繁忙的東西。調用

    Task.Run(()=> GetBigList())

,當你需要的結果等待。

private async Task<List<MyObject>> GetBigListAsync() 
{ 
    var myTask = Task.Run(() => GetBigList()); 
    // your thread is free to do other useful stuff right nw 
    DoOtherUsefulStuff(); 
    // after a while you need the result, await for myTask: 
    List<MyObject> result = await myTask; 

    // you can now use the results of loading: 
    ProcessResult(result); 
    return result; 
} 

再次:如果你有什麼有用的,而另一個線程加載列表(像保持UI響應)做的,如果你是快不這樣做,或至少測量。

,幫助我理解異步等待其他文章均 - Async await,由曾經如此有用斯蒂芬·克利裏, - 還有一點點更先進:Async-Wait best practices

相關問題