2014-01-23 71 views
0

所以我只是在c#中用Task類做一些實驗,發生下面的事情。在同一個對象上操作的幾個任務

這裏是我稱之爲

static async Task<List<int>> GenerateList(long size, int numOfTasks) 
{ 
    var nums = new List<int>(); 

    Task[] tasks = new Task[numOfTasks]; 

    for (int i = 0; i < numOfTasks; i++) 
    { 
     tasks[i] = Task.Run(() => nums.Add(Rand.Nex())); // Rand is a ThreadLocal<Random> 
    } 

    for (long i = 0; i < size; i += numOfTasks) 
    { 
     await Task.WhenAll(tasks); 
    } 

    return nums; 
} 

我這樣調用

var nums = GenerateList(100000000, 10).Result; 

此方法之前,我用任務產生了像4-5秒。如果我通過10-20個任務執行此方法後,生成時間降低到1,8-2,2秒,但通過該方法返回的List具有numOfTask個元素所以在這種情況下返回十個數的List。可能是我寫錯了什麼。這裏可能是什麼問題。或者可能有另一種解決方案。我希望有很多任務可以在同一個列表中添加數字,這樣生成時間至少要快兩倍。在此先感謝

回答

2

WhenAll不運行任務;它只是(異步)等待它們完成。你的代碼只能創建10個任務,所以你只能獲得10個數字。另外,正如@Mauro指出的那樣,List<T>.Add不是線程安全的。

如果你想要做的並行計算,然後用Parallel或並行LINQ,不async

static List<int> GenerateList(int size, int numOfTasks) 
{ 
    return Enumerable.Range(0, size) 
     .AsParallel() 
     .WithDegreeOfParallelism(numOfTasks) 
     .Select(_ => Rand.Value.Next()) 
     .ToList(); 
} 
-1

要添加到列表下面的循環中,其運行的只有10次

for (int i = 0; i < numOfTasks; i++) 
    { 
     tasks[i] = Task.Run(() => nums.Add(Rand.Nex())); // Rand is a ThreadLocal<Random> 
    } 

可以改爲做

for (int i = 0; i < numOfTasks; i++) 
    { 
     tasks[i] = new Task(() => nums.Add(Rand.Nex())); 
    } 
+0

我想要做的是有假設10的任務,將號碼添加到列表和運行它們秒任務 – Dimitri

+0

我可以運行任務數組而無需在循環中獨特地運行它們中的每一個? – Dimitri

+0

這不起作用,它會創建未啓動的「任務」,然後永遠不會啓動它們。即使你這樣做,你也只能啓動一次「Task」。 – svick

1

正如斯蒂芬解釋說,你只創建10個任務。

另外,我相信通用列表上的Add操作不是線程安全的。您應該使用鎖定機制,或者如果您的目標是框架4或更高版本,請使用thread-safe collections

+0

我沒有看到問題中的任何代碼將關閉循環變量。 – svick

+0

你說得對。我的錯。 –

相關問題