我如何重构这个ForEach(.)代码来使用Parallel.ForEach(.) ?
本文关键字:ForEach 代码 Parallel 何重构 重构 | 更新日期: 2023-09-27 17:50:26
我有一个对象列表,我希望从一个源复制到另一个。有人建议我可以使用Parallel来加快速度。ForEach
如何重构以下伪代码以利用Parallel.ForEach(..)
?
var foos = GetFoos().ToList();
foreach(var foo in foos)
{
CopyObjectFromOldBucketToNewBucket(foo, oldBucket, newBucket,
accessKeyId, secretAccessKey);
}
CopyObjectFromOldBucketToNewBucket
使用Amazon REST api将项从一个桶移动到另一个桶。
欢呼:)
Parallel
实际上不是这里的最佳选择。Parallel
将并行运行您的代码,但是对于每个到AWS的请求,仍然会使用一个线程池线程。使用BeginCopyObject
方法会更好地利用资源。这将不会耗尽等待响应的线程池,而只会在接收到响应并需要处理时使用它。
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方法
由于您的代码除了foos
之外没有任何依赖关系,您可以简单地执行:
Parallel.ForEach(foos, ( foo =>
{
CopyObjectFromOldBucketToNewBucket(foo, oldBucket, newBucket,
accessKeyId, secretAccessKey);
}));
请记住,I/O只能并行到一定程度,否则性能可能会下降。