库中的任务和 Parallel.Invoke,使用它是个坏主意吗?

Task and Parallel.Invoke in a library, is it a bad idea to use it?

我读过以这种方式做一个假的异步方法是个坏主意:

public int myMethodSyn()
{
    //sync operations

    return result;
}

public async int myMethodAsync()
{
    return await Task.Run(myMethodSync);
}

我阅读它的原因之一是,例如,ASP 可能会遇到此类库的可伸缩性问题,因为任务使用线程池,而 ASP 需要线程池来参加每个电话会议。所以库可以消耗线程池al block的所有线程ASP。所以最好让客户端决定如何使用线程池。

如果没记错的话,Parallel.Invoke 也使用线程池来并行 运行 方法,所以我想如果我在我的库中使用一个使用 parallel.Invoke 的方法,或 parallel.Foreach 或任何这种并行 运行 代码的方法,我都会遇到同样的问题。是真的吗?

我的想法是 运行 两个方法并行,因为它们是独立的,如果我 运行 它们并行,我可以获得更好的性能。所以我会有这样的东西:

public int myMainMethodSync()
{
    int result01 = myMethod01Sync();
    int result02 = myMethod02Sync();
    return result01 + result02;
}

private void myMethod01Sync()
{
}

private void myMethod02Sync()
{
}

public int myMainMethodAsync()
{
    Task myTsk01 = Task.Run(myMethod01Sync);
    Task myTsk02 = Task.Run(myMethod02Sync);
    Task.WhenAll(myTsk01, myTsk02);

    return myTsk01.Result + myTsk02.Result;
}

public int Task myMainMethodParallel()
{
    int result01;
    int result02;
    Parallel.Invoke(() => result01 = myMethod01Sync(),
                    () => result02 = myMethod02Sync());

    return result01 + result02;
}

想法是有一个同步方法,运行 两种方法同步。所以使用该库的客户端都知道该方法不会使用线程池。

稍后我有两个选项可以同时 运行 方法,使用任务或使用 parallel.Invoke。

在任务的情况下,我使用了伪造的异步方法,因为我将同步方法包装在一个任务中,该任务使用线程池中的两个线程。如果我没记错的话,不推荐这个。

另一个选项是使用 Parallel.Invoke,它也使用线程池中的线程,所以我猜它和任务有同样的问题,所以我想也不推荐它。

在我的情况下,我更愿意使用任务,因为我可以根据条件决定何时 运行 method02Sync,例如,根据一些条件,这样我可以节省分配线程的成本运行第二种方法如果我知道在某些情况下不需要它。我想在 parallel.Invoke 这是不可能的。

但是,我认为在这种情况下,我也是如何实现同步方法的,我让客户端选择它认为在其情况下更好的方法,所以在异步方法?

如果任务和 Parallel.Invloke 这两个解决方案都不好,那么不建议 运行 库中的并行代码,只在顶层使用它,在 UI还是图书馆的客户?因为我猜想在这种情况下使用并行是非常有限制的,因为在顶层,在 UI 中,如果它决定可以使用并行是不可能的,因为告诉库使用线程与否,因为它没有并行方法。

总而言之,我的解决方案公开同步和异步方法是个坏主意吗?在库中使用任务或并行代码是个坏主意吗?如果其中之一是更好的选择,哪一个?

谢谢。

is my solution, expose sync and async methods a bad idea?

让我重新表述问题以使其更笼统:

Is it a good idea to expose two versions of a method with different performance characteristics?

我认为大多数时候,这是个坏主意。你的图书馆的 API 应该是明确的,你不应该让你的图书馆的用户不断地在这两个选项之间进行选择。我认为作为图书馆作者,您有责任做出决定,即使这对您的某些用户来说是错误的。

如果这两个选项之间的差异很大,您可以考虑采用某种方法让您的用户在它们之间进行选择。但我认为有两个单独的方法是错误的选择,像可选参数这样的东西会是更好的方法,因为这意味着有一个明确的默认值。

我能想到的一个例外是两种方法的签名是否不同,就像真正的异步方法一样。但我认为这不适用于您使用 Tasks 来并行化 CPU 绑定方法。

Is it bad idea to use task or parallel code in the libraries?

我认为你应该谨慎使用它们。如果您的图书馆使用更多资源(此处为线程)来提高自身速度,您的用户可能会不高兴,这是对的。另一方面,大多数并行化代码的方法都足够智能,即使可用线程池线程的数量有限,它们仍然可以正常工作。因此,如果您测量到通过并行化代码获得的加速显着,我认为可以这样做。

If one of them it is better option, which one?

我认为这更像是您更喜欢哪一种代码风格的问题。 Parallel.Invoke()有两个动作和同步等待两个Task的性能特征应该是可以比较的。

不过请记住,您对 Task.WhenAll 的调用实际上并没有做任何事情,因为 WhenAll returns a Task 在其所有组件 Task 完成时完成。您可以改为使用 Task.WaitAll,但我不确定这有什么意义,因为您已经通过访问 Results 隐含地等待两个 Tasks。