C#使并发执行异步

C# making concurrent executing asynchronous

我目前正在努力提高我对多线程,尤其是 TPL 的理解。 许多构造完全有意义,我可以看到它们如何提高可伸缩性/执行速度。

我知道对于不占用线程的异步调用(如 I/O 绑定调用),Task.WhenAll 是最合适的。 不过,我想知道的一件事是使 CPU 绑定工作的最佳实践,我想 运行 并行异步。

要使代码 运行 并行,显而易见的选择是并行 class。 例如,假设我有一个数据数组,我想执行一些数字 c运行ching on:

string[] arr = { "SomeData", "SomeMoreData", "SomeOtherData" };
Parallel.ForEach(arr, (s) =>
{
    SomeReallyLongRunningMethod(s);
});

这将 运行 并行(如果分析器认为并行比同步快),但它也会阻塞线程。

现在我想到的第一件事就是把它全部包装在 Task.Run() ala:

string[] arr = { "SomeData", "SomeMoreData", "SomeOtherData" };
await Task.Run(() => Parallel.ForEach(arr, (s) =>
{
    SomeReallyLongRunningMethod(s);
}));

另一种选择是使用单独的任务返回方法或将其内联并使用 Task.WhenAll,如下所示:

static async Task SomeReallyLongRunningMethodAsync(string s)
{
    await Task.Run(() =>
    {
        //work...
    });
}
// ...
await Task.WhenAll(arr.Select(s => SomeReallyLongRunningMethodAsync(s)));

我的理解是,选项 1 创建了一个完整的任务,在它的生命周期中,将占用一个线程,让它坐在那里等待 Parallel.ForEach 完成。 选项 2 使用 Task.WhenAll(我不知道它是否占用线程)来等待所有任务,但必须手动创建任务。我的一些资源(特别是 MS ExamRef 70-483)明确建议不要为 CPU 绑定的工作手动创建任务,因为并行 class 应该用于它。

现在我想知道最佳性能版本/最佳实践,以解决希望可以等待的并行执行问题。 我希望一些更有经验的程序员能为我阐明这一点!

选项 1 是可行的方法,因为用于任务的线程池中的线程也将在并行 for 循环中使用。

您真的应该为此使用 Microsoft 的 Reactive Framework。这是完美的解决方案。你可以这样做:

string[] arr = { "SomeData", "SomeMoreData", "SomeOtherData" };

var query =
    from s in arr.ToObservable()
    from r in Observable.Start(() => SomeReallyLongRunningMethod(s))
    select new { s, r };

IDisposable subscription =
    query
        .Subscribe(x =>
        {
            /* Do something with each `x.s` and `x.r` */
            /* Values arrive as soon as they are computed */
        }, () =>
        {
            /* All Done Now */
        });

这里假设SomeReallyLongRunningMethod的签名是int SomeReallyLongRunningMethod(string input),不过应付别的东西就容易了。

都是运行多线程并行

如果您需要编组回 UI 线程,您可以在 .Subscribe 调用之前使用 .ObserveOn 来完成。

如果你想提前停止计算你可以调用subscription.Dispose().