1

我想知道是否有人知道并发(即多线程、并行等)编程语言的设置使得各个线程不会仅仅因为操作系统未能为它们提供 CPU 时间而彼此落后。我什至不确定装配是否可以避免这种情况。:P 但显然,我不确定,因此提出了这个问题。

我并不是说程序需要实时访问 CPU 周期,而是说线程不应该不同步。此外,如果该语言编译为二进制可执行文件而不是字节码,或者只是由解释器运行,那将是非常好的。

4

2 回答 2

4

我相信没有这样的事情。

原因是多个线程只有在不同的内核上执行才能真正并行执行。事实上,在多核处理器出现之前,技术上不可能同时运行(计算)不同的线程。

现代操作系统使用大量进程,因此使用大量线程(至少在逐个进程中,线程是进程的“工作”部分)。尽管有多核处理器,但在所有常见用法中,系统上的活动线程仍然比可用内核多。

当我写这些行时,我有 357 个线程活动用于“仅”8 个可用内核。

这就是调度程序的用途。它们在不同线程之间共享可用的计算时间,以避免饥饿并产生同时执行的错觉。

为了保证不同的线程同时运行并且不时不时地被放置,您应该修改操作系统的调度程序,如果可能的话,这至少是一个坏主意。

解释器的使用无济于事,因为它运行多线程应用程序的唯一方法是创建解释线程,这将有相同的问题

为了确保不同的线程同步,您应该使用屏障或信号量,因为您将永远无法修改用户计算机的操作系统调度程序


注意:在 HPC 应用程序中,研究人员尽量避免在上下文切换中浪费时间(保存线程运行的环境以便稍后恢复它的操作)。因此,他们根据可用内核分配线程(通常他们只为操作系统和 I/O 留下一个内核)并将其他线程固定到特定内核。这有助于他们确保尽可能高效地完成计算。

然而,这并不能保证同步,并且可能仍然需要使用特定的机制,如屏障。

于 2012-09-18T07:02:49.113 回答
0

使用现代处理器,很难确保任何特定的计算以绝对已知的速率进行。

例如:发生缓存未命中的线程可能需要比缓存命中的同一线程多几百个周期。所以现在速度取决于缓存中的内容。缓存中的内容取决于过去线程执行的复杂控制和数据流。有很多不受控制的延迟来源(管道中断、取决于操作数的可变长度指令执行、OOO CPU 中的内部资源争用、通过各种内存层次结构和跨总线到其他 CPU 的内存延迟、消息传输/接收时间……)

因此,要使线程以完全相同的速度运行,需要大量的控制或预知能力,而这是您几乎无法获得的。(超级计算的人几乎会关闭操作系统以最小化背景噪音,例如,随机发生的中断。即使这样也无济于事)。

更好的方法是让线程发出信号,表明他们已经完成的工作可供另一个需要它的人使用。如果信号/等待很少发生,那么它会被线程的计算工作所淹没,并且处理器被有效地使用。

实现上述目标还是很困难的。如果你在所有 CPU 上进行相同的计算[例如,大数据并行计算],并且非常有规律,那么总体速率可能非常相似;最后你仍然需要一些(障碍)同步,以确保它们都回到同步状态。

在每个 CPU 上将所有计算组织为“相同”是非常困难的。您更有可能有很多不规则(不同大小)的计算“颗粒”。如果您可以跟踪这些,那么您可以将它们分布在许多线程/CPU 上,依靠各个颗粒之间的显式同步以使它们整体正常工作,并将新颗粒交给突然空闲的 CPU 以保持忙碌。这可以通过“工作窃取”的概念很好地完成:每个 CPU 都有一个可以运行的未执行颗粒池,并尽可能快地处理它们。谷物可能会制造更多的谷物(如果你用完了,你就完成了计算!)。如果一个 CPU 的颗粒池变空,它会从池中为其他 CPU 窃取工作。一个工作窃取调度器很难构建。他们必须是对的,

我们的PARLANSE并行编程语言旨在处理此类问题。我们在代表程序的非常大的图表上运行它;它往往会为图中每个适度半径的补丁产生一些工作。在这样的图中有一百万个节点,我们有很多工作要做。

于 2015-05-01T05:37:49.597 回答