2017-08-24 76 views
0

我不明白爲什麼這個測試顯示lambda運行一次。我只能看到它可能產生0或10000.但只有一次?理想情況下,我想要執行所有任務,就像Task.WhenAll所建議的工具提示文檔一樣。任務不能在enumerable.repeat中運行

[Fact] 
    public async Task FireLotsOfQueries() 
    { 
     var counter = 0; 
     var taskList = Enumerable.Repeat(Task.Run(async() => 
     { 
      ++counter; 
      await Task.Delay(1000); 
     }), 10000); 
     await Task.WhenAll(taskList); 
     Assert.Equal(10000, counter); 
    } 

結果:

Xunit.Sdk.EqualException:Assert.Equal()失敗預期:10000 實際:1

+2

'++ counter'是不是線程安全的,你需要使用'Interlocked.Increment(ref counter);'如果你想從多個線程更新一個int。 –

+0

@ScottChamberlain幸運的是,代碼不能從多個線程訪問它。如果代碼更改爲同時從多個線程訪問「counter」,那麼是的,這就成了一個問題。 – Servy

回答

6

問題是你沒有創建1000任務。您正在創建一個包含1000次相同任務的枚舉。試試這個:

public async Task FireLotsOfQueries() 
{ 
    var counter = 0; 
    var taskList = Enumerable.Repeat(0, 10000) 
     .Select(_=> Task.Run(async() => 
     { 
      ++counter; 
      await Task.Delay(1000); 
     })); 
    await Task.WhenAll(taskList); 
    Assert.Equal(10000, counter); 
} 

你一定會需要櫃檯周圍一些鎖定爲這個版本也失敗了,但計數器將是一個價值接近10000

-1

共享在您運行任務counter是真正的問題。 您可以通過使用lock聲明,TaskCompletionSource解決這個問題的代碼,或Interlocked.Increment接近

要了解爲什麼counter編譯器優化了緩存的結果檢查共享 ​​

[Fact] 
public async Task FireLotsOfQueries() 
{ 
    var static volatile counter = 0; 
    var taskList = Enumerable.Repeat(Task.Run(async() => 
    { 
     Interlocked.Increment(ref counter); 
     await Task.Delay(1000); 
    }), 10000); 
    await Task.WhenAll(taskList); 
    Assert.Equal(10000, counter); 
}