2

我已經得到了一個我想從一個源複製到另一個對象的列表。 It was suggested that I could speed things up使用Parallel.ForEach如何重構此ForEach(..)代碼以使用Parallel.ForEach(..)?

如何重構以下pseduo代碼以利用Parallel.ForEach(..)

var foos = GetFoos().ToList(); 
foreach(var foo in foos) 
{ 
    CopyObjectFromOldBucketToNewBucket(foo, oldBucket, newBucket, 
     accessKeyId, secretAccessKey); 
} 

CopyObjectFromOldBucketToNewBucket使用Amazon REST API將項目從一個存儲桶移動到另一個存儲桶。

乾杯:)

回答

3

Parallel其實並不是這裏最好的選擇。 Parallel將並行運行您的代碼,但仍會爲AWS的每個請求使用線程池線程。相反,使用BeginCopyObject方法會更好地利用資源。這不會佔用等待響應的線程池線程,而只會在收到響應並需要處理時才使用它。

下面是如何使用Begin/End方法的簡化示例。這些不是特定於AWS的,而是在整個.NET BCL中找到的模式。

public static CopyFoos() 
{ 
    var client = new AmazonS3Client(...); 
    var foos = GetFoos().ToList(); 
    var asyncs = new List<IAsyncResult>(); 
    foreach(var foo in foos) 
    { 
     var request = new CopyObjectRequest { ... }; 

     asyncs.Add(client.BeginCopyObject(request, EndCopy, client)); 
    } 

    foreach(IAsyncResult ar in asyncs) 
    { 
     if (!ar.IsCompleted) 
     { 
      ar.AsyncWaitHandle.WaitOne(); 
     } 
    } 
} 

private static EndCopy(IAsyncRequest ar) 
{  
    ((AmazonS3Client)ar.AsyncState).EndCopyObject(ar); 
} 

對於產品代碼,您可能需要跟蹤您發送的請求數量,並且只發送有限數量的任何時間。測試或AWS文檔可能會告訴您有多少併發請求是最佳的。

在這種情況下,當請求完成時,我們並不需要做任何事情,所以您可能會試圖跳過EndCopy調用,但這會導致資源泄漏。無論何時調用BeginXxx,都必須調用相應的EndXxx方法。

+0

您能否提供一些關於'BeginCopyObject'的更多信息? – 2011-04-19 02:16:46

+0

@ Pure.Krome,我添加了一個重要細節的示例。 – 2011-04-19 15:09:31

3

因爲你的代碼沒有比foos其他任何依賴關係,你可以簡單地做:

Parallel.ForEach(foos, (foo => 
{ 
    CopyObjectFromOldBucketToNewBucket(foo, oldBucket, newBucket, 
             accessKeyId, secretAccessKey); 
})); 

但是要記住,那I/O只能以並行在某種程度上,表現可能實際上會降低。

+1

如果這些任務依賴於I/O並且長時間運行,那麼可能不是最好的方法。 – 2011-04-20 14:31:36