并行任务的最大数量有一个通用规则吗

本文关键字:规则 有一个 最大数 并行任务 | 更新日期: 2023-09-27 18:00:05

我第一次使用并行任务,而不是使用传统的线程池。在我的应用程序中,我允许用户输入为完成作业而启动的任务数。(工作可能很大)。我注意到,如果我允许10个左右的任务,应用程序就会挂起,而且由于使用了资源,我的性能实际上会变差。

我想知道处理器的数量和最大任务量之间是否有任何相关性,这样我就可以限制用户pc的最大任务量,这样就不会减慢速度。

并行任务的最大数量有一个通用规则吗

没有,主要是因为没有任务的定义。一个任务可以是CPU密集型的(限制就像Cores*因子)、IO密集型(限制可能很低),也可以是有限资源的网络密集型(不喜欢同时处理1000个请求)。

因此,作为一名程序员,你应该开动脑筋,想出一个概念,然后验证它,然后将其放入你的程序中,这取决于任务的实际内容以及瓶颈的预测位置。这样的规划可能很复杂——非常复杂——但大多数时候都很简单。

TPL将自动更改任务的调度方式,并随着时间的推移添加或删除ThreadPool线程。这意味着,如果有足够的时间和类似的工作,默认行为应该改进为最佳选项。

默认情况下,它将通过使用比核心更多的线程来启动,因为许多任务不是"纯CPU"。考虑到您看到额外的任务导致速度减慢,您可能存在资源争用(通过锁定),或者您的任务受CPU限制,并且任务比处理器核心多会导致速度减慢。如果这会有问题,您可以创建一个自定义的TaskScheduler来限制一次允许的任务数量,例如LimitedCurrentTaskScheduler。这允许您将任务数量限制为纯CPU场景中的处理器数量。

如果您的任务受其他因素(如IO)的约束,那么您可能需要进行配置以确定并发调度任务的数量和吞吐量之间的最佳平衡,尽管这将是特定于系统的。

假设您的任务是CPU密集型的(即,它们不执行大量i/O阻塞,如读取文件),您可能希望将并行任务的数量限制为应用程序可用的CPU核心数量。例如,如果您的应用程序在具有四核处理器(即4核)的计算机上运行,请将其限制为4个同时执行的任务。

如果你的任务受到CPU以外的其他因素的限制(例如磁盘访问、网络访问等),那么你需要计算出每个任务平均占用的资源份额。如果你知道平均值,那么为了充分利用你的资源,你应该运行的任务数量是100 / average

我带着这个来的

一般来说,这是指导方针:

number-of-tasks = (task-total-run-time / task-cpu-bounded-run-time) * number-of-cores

对于实际计算:

number-of-tasks = Ceil(Avg(task-total-run-time / task-cpu-bounded-run-time) * Max((number-of-cores - 1), 1))


解释:

number-of-tasks-在并行中运行的任务数

task-total-run-time-异步方法的总运行时间(以毫秒为单位)

task-cpu-bounded-run-time-异步方法使用核心cpu的时间(以毫秒为单位)

number-of-cores-可用的真实或虚拟核心的数量(例如,在docker容器的情况下),减去1,因为一个核心用于主线程而不是工作线程,对于1核心环境,它将是最小的1


注意:

  • 如何了解Avg(task-total-run-time / task-cpu-bounded-run-time):A需要在真实环境中进行测量,以确定平均时间比是多少
  • 即使任务的最大数量几乎完全不受cpu限制,也应该有一些上限,例如128,这应该也要考虑


示例:

对于8核心,平均运行时间如下

public async Task UpdateScoreAsync(string requestId)
{
    var res = await GetFromDB(requestId).ConfigureAwait(false); // not cpu bounded, 10 seconds
    int resScore = CalculateScore(res); // cpu bounded, 20 seconds
    await UpdateScoreInDB(requestId, resScore).ConfigureAwait(false); // not cpu bounded, 20 seconds
}

因此,你可以运行的任务数量(如果这是你唯一拥有的)是12任务

12 = Ceil(((10 + 20 + 20) / (10 + 20)) * (8 - 1))