2012-08-27 18 views
1

我有一個需要同時處理的文件列表。我試圖使用ParallelQuery類的ForAll擴展方法。我沒有要處理的文件,所以我使用了ForAll。ParallelQuery.ForAll方法中的增量ID

這裏是我的示例代碼:

List<FileInfo> files = GetFilesToProcess(); 

files.AsParallel().ForAll(f => { // Process file here }); 

它的偉大工程,但現在我需要爲每一個文件,我不知道如何做到這一點不改變AsParallel.ForAll到的ForEach一個唯一的整數ID 。

我讀了一些我需要作爲聯鎖的地方,但仍然會有問題。

希望你能給我一個主意。

謝謝!

回答

2

您可以使用Interlocked.Increment生成的ID,或者你可以直接使用索引:

List<FileInfo> files = GetFilesToProcess(); 

files.AsParallel().Select((f, i) => new {File=f, ID=i}) 
    .ForAll(fp => 
      { 
       FileInfo file = fp.File; 
       int id = fp.ID; // ID is the index in the list 

       // Process file here 
      }); 

如果你想使用Interlocked.Increment,你可以這樣做:

List<FileInfo> files = GetFilesToProcess(); 
int globalId = -1; 

files.AsParallel().ForAll(f => 
         { 
           // Process file here 
           int id = Interlocked.Increment(ref globalId); 
           // use ID 
         }); 

話雖這麼說,如果你的整個目標是對一個集合做「工作」,我會建議把它寫成一個Parallel.For或者Parallel.ForEach。這是更爲明確的,因爲你不使用LINQ風格的語法產生副作用的唯一目的:

List<FileInfo> files = GetFilesToProcess(); 
Parallel.For(0, files.Count, i => 
{ 
    var file = files[i]; 
    // Use i and file as needed 
}); 
+0

嗨裏德,感謝您提出的解決方案和答覆。我只想澄清一下,如果我使用Parallel For/ForEach,它將像ForAll一樣並行執行?對不起,如果你認爲這是一個愚蠢的問題。只是想確定。 – lionheart

+0

@lionheart是的 - 這是兩種不同的方法。通常,如果您正在執行某種形式的過濾操作('.Where')或映射操作('.Select'),則可以使用PLINQ('.AsParallel()')。剛剛引入'.ForAll()'方法來簡化您在處理「查詢」結果時的工作。如果你的目標僅僅是「並行地做一些工作」,那麼'Parallel.For'和'Parallel.ForEach'更合適。對於一個很好的理由,爲什麼,請閱讀:http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx –

+0

太棒了!謝謝里德! – lionheart

0

如果你真的必須,那麼你可以有你處理過的Interlocked.Incrementint

使用源的索引是一個更好的選擇,因爲這是從分區器已經可用的信息,並且即使是這樣的光共享Interlocked給出,仍然共享。

或者,您可以跳過並使用某種UUID。在這種情況下,這可能是沉重的值得(索引是好的和輕的)。我提到它是因爲「我可以在並行任務之間零共享的情況下做到這一點嗎?」應該始終考慮,即使後來被解僱。