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