【问题标题】:Parallelizing IO Bound (Network) ForEach Loop并行化 IO 绑定(网络)ForEach 循环
【发布时间】:2023-04-10 00:00:01
【问题描述】:

根据选择的选项,我有几种不同的方法可以在我的应用程序中将整个目录上传到 Amazon S3。目前,其中一个选项将并行执行多个目录的上传。我不确定这是否是个好主意,因为在某些情况下它会加快上传速度,而在其他情况下会减慢速度。当有一堆小目录时,速度似乎会加快,但如果批处理中有大目录,速度就会变慢。我正在使用下面看到的并行 ForEach 循环并利用 AWS API 的 TransferUtility.UploadDirectoryAsync() 方法:

Parallel.ForEach(dirs,myParallelOptions, 
                   async dir => { await MyUploadMethodAsync(dir) };

TransferUtility.UploadDirectoryAsync() 方法在 MyUploadMethodAsync() 中的位置。 TransferUtility 的上传方法都执行单个文件的部分并行上传(如果大小足够大的话),因此执行目录的并行上传也可能是矫枉过正。显然,我们仍然受限于可用的带宽量,所以这可能是一种浪费,我应该只使用带有 UploadDirectoryAsync() 方法的常规 foreach 循环。谁能提供一些关于这是否不适合并行化的见解?

【问题讨论】:

    标签: c# amazon-web-services parallel-processing task-parallel-library parallel.foreach


    【解决方案1】:

    你真的测试过这个吗?您使用它的方式,Parallel.ForEach 可能会在任何MyUploadMethodAsync 完成之前返回,因为async lambda:

    Parallel.ForEach(dirs,myParallelOptions, 
        async dir => { await MyUploadMethodAsync(dir) };
    

    Parallel.ForEach 适用于 CPU 密集型任务。对于 IO-bound 任务,您可能正在寻找这样的东西:

    var tasks = dirs.Select(dir => MyUploadMethodAsync(dir));
    await Task.WhenAll(tasks);
    // or Task.WaitAll(tasks) if you need a blocking wait
    

    【讨论】:

    • 我确实测试了几次,但正如我在帖子中提到的那样,根据目录大小,我得到了混合的结果。 Parallel.ForEach 在每个 MyUploadMethodAsync 方法之前返回是绝对正确的。我在跟踪中看到了这一点,但这是意料之中的,因为它们是异步操作。我会试试这个版本,看看它是否能提高性能。
    • @JNYRanger,您传递给Parallel.ForEach 的是async void lambda,甚至不是async Task lambda。当Parallel.ForEach 返回时,您无法跟踪完成状态、检查结果并处理每个MyUploadMethodAsync 可能引发的任何异常(并且其中大部分仍处于未决状态)。
    • 非常感谢,这成功了。我不仅能够更好地处理错误,而且将性能提高了 25% 以上!我违反了自己制定async void 方法的规则。再也不会了。
    • 从此帖子stackoverflow.com/questions/8505815/…TaskContinuationOptions.AttachedToParent 将解决您的其他问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    • 1970-01-01
    相关资源
    最近更新 更多