我试图让我的头脑围绕 C++ 中的多线程,想出一个适合我的通用实现。每个人都有不同的实现,Awesome CPP列出了 39 个库。在我看来,这是一个与任何领域的任何后勤调度问题相同的后勤问题。
在我看来,有两种明显的方法可以重复执行这项工作abc
:
分成
abc
3 个单独的任务:a
,b
&c
。产生 x 个线程。排队。进来的作业被添加到队列中。每个线程从队列中抓取下一个任务,并在任务结束时将其放回队列中等待下一个任务。他们可以直接访问队列,或者他们都可以与为他们提供任务的中央“管理器”或“调度器”线程进行通信。abc
独立地在 x 个单独的线程上按顺序执行(并行性。)
(1) 存在一个问题,即在保持队列和处理其上的竞争条件时可能存在大量开销。(1)在其他方面是直观的,对我来说很有意义。这就是我在现实生活中遇到现实生活中的问题时会做的事情。从字面上看,这就是公司在现实世界中的运作方式。
(2)存在任何阻塞导致整个线程阻塞,使CPU线程空闲的问题。并且(2)在较少的用例中的灵活性和适用性要差得多。从好的方面来说,任务之间没有开销。
问题1:(1)不也有同样的阻塞问题吗?如果一个线程从文件中读取,它必须等待磁盘。这通常是如何解决的,是否有某种方法可以在它执行诸如从磁盘读取或写入之类的操作时暂时返回,或者这通常只是通过运行的线程多于 CPU 线程并希望一次不会有太多块来解决?
在我看来,(1)显然是更好的解决方案,除了它将任务限制为中型到大型任务。用它来做一些简单的数学并行化(只是一个例子)是没有意义的,因为处理队列需要比实际处理任务更长的时间。因此,任何给定任务的 (1) 值与存储机制(队列)的开销和任务大小之间的差异成反比。从表面上看,这听起来不错,直到您意识到拆分为任务的效率本身与任务的大小成正比。简而言之:理论上您希望每个任务都较小以提高整体效率,但实际上您希望每个任务都较大以最小化队列的开销。
很明显,需要一些存储机制,因为如果没有记录机制,您将无法跟踪某件事,它不一定是严格的队列,而是在等待被拾取时将任务记录在内存中的任何形式。队列的优化(我用的是松散的词,不是严格意义上的队列类型)是这里的#1重要因素。任务接收其有效载荷的成本越低越好。
这让我想到了问题 2:这就是 C++20 协程有用的地方吗?我花了几个小时阅读协程教程,但仍然不清楚它们有什么用处。我想我明白他们的所作所为。如果我做对了,他们允许一种特殊类型的函数(协程)在中间暂停,将其处理连同有效负载一起返回给调用者,调用者稍后可以恢复它。但我为什么要这样做?我不能通过将函数分成两部分来做到这一点吗?
问题 3:协程是否意味着任务调度程序线程使用协程以某种方式优化队列?还是只是为了让您线性编写代码,然后将这些产量放入其中以将其分解?在这种情况下,如果我已经按照设计将我的工作分成单独的任务,它对我没有用处?
问题4:我想在这里重新发明轮子吗?这个问题已经解决了吗?如果是这样,为什么会有这么多不同的实现?