【问题标题】:Task and Parallel.Invoke in a library, is it a bad idea to use it?库中的 Task 和 Parallel.Invoke,使用它是不是一个坏主意?
【发布时间】:2017-11-13 23:00:51
【问题描述】:

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

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 的条件,因此如果我可以节省分配线程来运行第二种方法的成本知道在某些情况下不需要它。我猜是并行的。调用这是不可能的。

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

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

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

谢谢。

【问题讨论】:

  • 您调用的每个方法通常需要多长时间?并行运行它们能给你带来多大的加速?
  • 我的问题更多是关于尝试了解任务和 Parallel.Invoke 之间的区别以及开发使用并行的库的最佳方法,如果开发使用并行的库是一个好主意。

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


【解决方案1】:

我的解决方案,公开同步和异步方法是个坏主意吗?

让我重新表述这个问题,使其更笼统:

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

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

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

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

在库中使用任务或并行代码是个坏主意吗?

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

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

我认为这更多地取决于您更喜欢哪种代码风格。 Parallel.Invoke() 两个action 同步等待两个Tasks 的性能特点应该是相当的。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-29
    • 1970-01-01
    • 2011-10-21
    • 2012-04-08
    • 1970-01-01
    • 2019-02-01
    • 2011-02-03
    相关资源
    最近更新 更多