2017-03-14 54 views
0

使用不帶async關鍵字的lambda表達式的LINQ表達式可以指定索引。對於example如何將索引添加到異步LINQ查詢

var list = FileList.Select((file, index) => new { Index=index, Filename=file }); 

我試圖同時使用async關鍵字來獲得指標。例如:

await Task.WhenAll(urlList.Select(async url => 
{ 
    byte[] urlContents = await GetWebPageAsync(url); 
    lock (Locker) { webResults.Add(URLContents); } 
})); 

我想獲得該指數,使得網頁內容可以被存儲在一個數組,而不是使用鎖語句或集合索引中進行搜索的原因。

當我嘗試向上述查詢添加一個索引時,它會給編譯器帶來錯誤。

有沒有辦法在上面的查詢中指定索引,或者可以使用另一個LINQ表達式(Select除外),它支持使用帶索引的異步lambda表達式?

+0

您不應該在預測中執行副作用。在正常的代碼中這已經夠糟的了,但是當處理多線程代碼時,處理起來更加困難。執行投影的lambda應返回操作的結果,而不是將它們添加到列表中。然後您可以使用返回序列的結果。 – Servy

回答

0

我剛剛意識到的是,代碼從await回來時總是單線程的 - 並且它始終與它被調用的線程相同。在這種情況下,它是一個用戶界面線程。所以,不需要鎖定語句。

爲了驗證這一點,我把幾個電話來獲取線程ID:

string ThreadID = Thread.CurrentThread.ManagedThreadId.ToString(); 
await Task.WhenAll(urlList.Select(async url => 
{ 
    string TaskThreadID = Thread.CurrentThread.ManagedThreadId.ToString(); 
    byte[] URLContents = await GetWebPageAsync(url); 
    string TaskThreadID2 = Thread.CurrentThread.ManagedThreadId.ToString(); 
    lock (locker) { webResults.Add(URLContents); } 
    })); 

他們都是相同的值。我對Task.WhenAll方法的工作原理有一種誤解。

即使在這種情況下,我不需要索引,但有時候它會有幫助。如果任何人都可以展示如何優雅地獲得指數,我會接受答案。

+0

對於優雅的解決方案,只需使用兩個選擇語句FileList.Select((file,index)=> new {Index = index,Filename = file});選擇(async data => {foo = data.Index; \\ ...});' –

+0

@ScottChamberlain我會試試看。 –

+0

@ScottChamberlain看起來它會工作,但代碼爲集合中的每個元素創建一個新對象。我不知道這是否比在集合中對每個url進行順序搜索(當集合很小時)來找到索引或在字典較大時使用Dictionary來更好。微軟應該添加一個可以與async一起使用的重載方法,以獲得集合中的索引 - 就像它處理常規的LINQ一樣。 –