我知道当我们想要更快地进行大数学计算时,通常的方法是使用多处理/并行处理:我们将作业分成4个部分,我们让4个CPU核心并行运行(并行化)。例如,在具有multiprocessing
模块的Python中,这是可能的:在4核CPU上,它允许使用计算机100%的处理能力,而不是单处理作业的25%。
但是,让我们说我们希望加快不易拆分的计算工作。
示例:我们获得了一个数字生成器函数generate(n)
,它将先前生成的数字作为输入,并且"据说它具有10 ^ 20作为句点"。我们想用以下伪代码检查这个断言:
a = 17
for i = 1..10^20
a = generate(a)
check if a == 17
而不是让计算机的4个CPU内核(3.3 Ghz)并行运行"而不是#34;总共有4个进程,是否可以模拟一个13.2 Ghz (4 * 3.3)的非常快速的单核CPU,用前面的代码运行一个进程?
这种技术适用于台式电脑吗?如果没有,是否可以在云计算平台(AWS EC2等)上使用?
答案 0 :(得分:2)
单线程性能非常有价值;编写顺序代码比显式公开线程级并行更容易。
如果在代码中没有并行性的情况下,有一种简单而有效的通用方法来执行您所要求的工作方式,那么它已经广泛使用。在多核CPU内部,或者在软件中,如果它需要更高级别/更大规模的代码转换。
无序CPU可以在单个线程中查找和利用指令级并行(短距离,如几百条指令),但是您需要显式的线程级并行来利用多个内核。
这与SoftwareEnginnering.SE上的How does a single thread run on multiple cores?类似,不同之处在于您已经排除了任何易于查找的并行性,包括指令级并行性。 (答案是:它不是。它是单核的硬件,在单个线程中找到指令级并行性;我的答案解释了一些微架构的细节,说明它是如何工作的。)
相反的过程:将一个大CPU转变为多个较弱的CPU确实存在,并且对于运行没有太多指令级并行性的多个线程非常有用。它被称为SMT (Simultaneous MultiThreading)。你可能听说过英特尔的超线程,这是SMT最广为人知的实现。它可以交换单线程性能以获得更高的吞吐量,从而使更多的执行单元能够在更多的时间内完成有用的工作。构建单个宽核心的成本至少增加了两倍,这就是为什么典型的台式机CPU不仅仅拥有一个带有8路SMT的大型核心。 (请注意,除非generate
函数具有一些内部指令级并行性,否则真正宽的CPU仍无助于完全依赖的指令流。)
generate()
函数,那么SMT会很好。如果没有SMT,您可以在一个线程中的两个generate
链之间交替使用软件,因此无序执行可能会同时处理来自两个依赖链的指令。
编译器在编译时自动并行化可能对于具有一些可见并行性的源,但如果generate(a)
不是“可分离的”(我认为不是正确的技术术语)那么你就没有运气。
e.g。如果它是return a + hidden_array[static_counter++];
那么编译器可以使用数学来证明并行对数组的块进行求和并添加部分和仍然会得到相同的结果。
但如果通过a
确实存在串行依赖(如even a simple LCG PRNG),并且该软件不知道任何数学技巧来打破依赖或将其缩小为封闭形式,那么你就是运气不好编译器确实知道像sum(0..n) = n*(n+1)/2
这样的技巧(稍微不同地评估以避免部分结果中的整数溢出),或者a+a+a+...
(n次)是a * n
,但这对此没有帮助。 / p>
答案 1 :(得分:2)
有一个主要在学术界研究的方案称为“线程分解”。它旨在或多或少地做你所要求的 - 给定一个单线程代码,它试图将其分解为多个线程,以便在多核系统上划分工作。这个过程可以由编译器完成(尽管这需要在编译时找出所有可能的副作用,这非常困难),JIT运行时或通过HW二进制翻译,但这些方法中的每一个都有复杂的限制和缺点。
不幸的是,除了自动化之外,这个过程几乎没有什么吸引力,因为它很难匹配一个人如何理解代码所做的真正的手动并行化。它也不是简单地根据线程数来扩展性能,因为它通常会以代码的形式产生大量开销,而且必须重复。
来自巴塞罗那UPC的一些好人的示例论文:http://ieeexplore.ieee.org/abstract/document/5260571/