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

时间:2017-11-12 11:33:30

标签: c# parallel-processing task-parallel-library

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

public int myMethodSyn()
{
    //sync operations

    return result;
}

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

我读过它的原因之一是因为例如ASP可能会出现这类库的可伸缩性问题,因为任务使用线程池而ASP需要线程池来参与每个调用。因此库可以使用线程池的所有线程来阻止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。

在任务的情况下,我使用伪异步方法,因为我在任务中包装sync方法,该方法使用来自线程池的两个线程。如果我没错,建议不要这样做。

另一种选择是使用Parallel.Invoke,它也使用来自线程池的线程,所以我猜它与任务有同样的问题,所以我想也不建议这样做。

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

但是,我认为在这种情况下,我也是如何实现同步方法的,我让客户端选择在它的情况下更好地考虑的方法,所以在异步方法中使用任务真的是一个不好的选择?

如果两个解决方案都不好,任务和Parallel.Invloke,那么不建议在库中运行并行代码,只在顶级,库或UI的客户端中使用它?因为我认为在这种情况下并行的使用是非常严格的,因为在顶层,在UI中,如果它决定它是可能的,则不可能使用parallel,因为告诉库使用线程与否,因为它不会没有平行的方法。

在sumary,我的解决方案,暴露同步和异步方法是一个坏主意?在库中使用任务或并行代码是不错的主意吗?如果其中一个是更好的选择,哪一个?

感谢。

1 个答案:

答案 0 :(得分:1)

  

是我的解决方案,暴露同步和异步方法是一个坏主意吗?

让我重新提出问题,使其更加笼统:

  

公开具有不同性能特征的方法的两个版本是一个好主意吗?

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

如果两个选项之间存在显着差异,您可以考虑一些让用户在其中进行选择的方法。但我认为有两个单独的方法是错误的选择,类似于可选参数的东西是更好的方法,因为这意味着有一个明确的默认值。

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

  

在库中使用任务或并行代码是不错的主意吗?

我认为你应该谨慎使用它们。如果您的库使用更多资源(此处为线程)以提高自身速度,那么您的用户可能会感到不满。另一方面,大多数并行化代码的方法足够智能,如果可用线程池线程的数量有限,它们仍然可以正常工作。所以,如果你测量通过并行化你的代码获得的加速是很重要的,我认为这样做是可以的。

  

如果其中一个是更好的选择,哪一个?

我认为这更像是一个你喜欢哪种代码风格的问题。具有两个操作并同步等待两个Parallel.Invoke()的{​​{1}}的性能特征应具有可比性。

尽管请注意,您对Task的致电确实没有做任何事情,因为Task.WhenAll 会返回一个WhenAll完成所有组件Task完成。您可以改为使用Task,但我不确定这是什么意思,因为您已经通过访问Task.WaitAll来隐式等待Task两个Result