gpt4 book ai didi

c++ - 多线程作业队列管理器

转载 作者:IT老高 更新时间:2023-10-28 12:39:32 24 4
gpt4 key购买 nike

我需要在交互式应用程序中管理占用大量CPU的多任务作业。就像背景一样,我的特定应用程序是工程设计界面。当用户为模型调整不同的参数和选项时,将在后台运行多个模拟,并在完成时显示结果,即使用户仍在编辑值也是如此。由于多次模拟需要花费可变的时间(有些是毫秒,有些是5秒钟,有些是10分钟),因此基本上是尽可能快地显示反馈,但是通常会中止以前开始但现在不再需要的作业,因为的用户更改已经使它们无效。不同的用户更改可能会使不同的计算无效,因此在任何时候我都可以运行10个不同的模拟。某些模拟具有依赖关系的多个部分(可以单独计算模拟A和B,但是我需要将它们的结果作为模拟C的种子,因此在启动C之前,我需要先等待A和B都完成)。

我非常有信心处理这种应用程序的代码级方法是某种多线程作业队列。这将包括以下功能:提交作业以执行,设置任务优先级,等待作业完成,指定依赖项(执行此作业,但仅在作业X和作业Y完成之后),取消符合某些条件的作业子集,查询哪些内容作业仍然存在,设置工作线程数和优先级,等等。而且多平台支持也非常有用。

这些不是软件中的新想法或新愿望,但是我处于应用程序的早期设计阶段,在这里我需要选择用于管理此类任务的库。过去,我用C语言编写了自己的粗线程管理器(我认为这是一种习惯),但是我想使用现代工具而不是以我以前的技巧为基础来开展工作。

首先想到的是运行OpenMP,但我不确定这就是我想要的。 OpenMP非常适合于精细并行化,自动展开循环等。虽然是跨平台的,但它也使用#pragmas入侵了您的代码。但是大多数情况下,它不是为管理大型任务而设计的。尤其是取消待处理的作业或指定依赖项。可能,是的,但这并不优雅。

我注意到Google Chrome uses such a job manager for even the most trivial tasks.的设计目标似乎是使用户交互线程尽可能轻巧,灵活,因此应该异步生成的所有内容都应该如此。从Chrome的源代码来看,这似乎不是一个通用库,但是,看看该设计如何使用异步启动来保持快速交互仍然很有趣。这与我正在做的事情越来越相似。

还有其他选择:

Surge.Act:一个类似于Boost的库,用于定义作业。它建立在OpenMP之上,但确实允许链接依赖关系,这很好。似乎没有一个可以查询的经理,可以取消工作的经理等。这是一个陈旧的项目,因此很难依靠它。

Job Queue非常接近我的想法,但这是一篇已有5年历史的文章,而不是受支持的库。

Boost.threads确实具有良好的平台独立同步性,但这不是作业管理器。 POCO具有非常干净的任务启动设计,但又不是用于链接任务的完整管理器。 (也许我虽然低估了POCO)。

因此,尽管有可用的选项,但我不满意,并且感到有再次推出自己的库的冲动。但是我宁愿使用已经存在的东西。即使经过搜索(在SO和Internet上),我也没有找到任何感觉合适的东西,尽管我认为这一定是经常需要的一种工具,因此肯定有一些社区库或至少是通用设计。
在SO上有一些关于postsjob queues,但似乎不适合。

我在这里的帖子是要问您我错过了哪些现有工具,和/或您如何滚动自己的多线程作业队列。

最佳答案

我们必须构建自己的作业队列系统来满足与您类似的要求(UI线程必须始终在33ms内响应,作业可以在15-15000ms内运行),因为实际上没有什么可以完全满足我们的需求,更不用说性能了。

不幸的是,我们的代码与专有获取一样专有,但是我可以为您提供一些最突出的功能:

  • 我们在程序开始时为每个内核启动一个线程。每个人都从全局作业队列中拉取工作。作业由一个功能对象和一组关联数据组成(实际上是对func_ptr和void *的详细说明)。不允许使用线程0(快速的客户端循环)来处理作业,而其余线程则可以尽力而为。
  • 作业队列本身应为无锁数据结构,例如lock-free singly linked list(Visual Studio comes with one)。避免使用互斥锁;队列的争用令人惊讶地高,并且获取互斥对象的代价很​​高。
  • 将作业所需的所有必要数据打包到作业对象本身中-避免将指针从作业返回到主堆中,在主堆中您必须处理作业和锁之间的争用以及所有其他缓慢而烦人的东西。例如,所有模拟参数都应放入作业的本地数据块中。结果结构显然需要比工作更久的东西:您可以通过以下方式处理此问题:a)卡在作业对象上,即使它们已经运行完毕(因此您可以从主线程使用它们的内容),或者b)为每个作业专门分配结果结构,并将指针填充到作业的数据对象中。即使结果本身不会存在于工作中,这也有效地赋予了工作对其输出内存的独占访问权限,因此您无需费心费力。
  • 实际上,我在上面做了一些简化,因为我们需要精确地编排哪些作业在哪个内核上运行,所以每个内核都有自己的作业队列,但这对您来说可能是不必要的。
  • 关于c++ - 多线程作业队列管理器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/565137/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com