我想知道在我的程序中,我是否只有一个线程,我可以写它,以便Quad核心或i7实际上可以使用不同的内核吗?通常,当我在Quad核计算机上编写程序时,CPU的使用率只会达到25%左右,而且工作似乎被分成了4个核心,任务管理器( Task )显示了这一点。(我编写的程序通常是Ruby、Python或PHP,所以它们可能没有那么优化)。
更新:如果我用C或C++编写它怎么办?
for (i = 0; i < 100000000; i++) {
a = i * 2;
b = i + 1;
if (a == ... || b == ...) { ... }
}然后在编译器中使用最高级别的优化。编译器能否使乘法发生在一个核上,而加法发生在另一个核上,从而使两个核同时工作?这不是一个相当容易的优化使用两个核心吗?
发布于 2009-05-18 09:30:11
不是的。您需要使用线程在多个CPU上并发执行多个路径(无论它们是真实的还是虚拟的).一个线程的执行本质上是绑定到一个CPU上的,因为这维护了语句之间的“先发生”关系,这是程序如何工作的核心。
发布于 2009-05-18 15:39:42
首先,除非在程序中创建了多个线程,否则该程序中只有一个执行线程。
看到25%的CPU资源被用于该程序,这表明每四个CPU中就有一个在100%时被使用,但所有其他核心都没有被使用。如果所有的核心都被使用,那么理论上这个进程就有可能占用100%的CPU资源。
另外,在Windows中,任务管理器中显示的图形是当时运行的所有进程的CPU利用率,而不仅仅是一个进程的CPU利用率。
其次,您所呈现的代码可以拆分为可以在两个单独的线程上执行的代码,以便在两个核心上执行。我猜您想要证明a和b是相互独立的,它们只依赖于i。在这种情况下,像下面这样分离for循环的内部可以允许多线程操作,从而提高性能:
// Process this in one thread:
for (int i = 0; i < 1000; i++) {
a = i * 2;
}
// Process this in another thread:
for (int i = 0; i < 1000; i++) {
b = i + 1;
}然而,棘手的是,如果需要计算来自两个单独线程的结果的时间,就像后面的if语句所暗示的那样:
for (i = 0; i < 1000; i++) {
// manipulate "a" and "b"
if (a == ... || b == ...) { ... }
}这需要查找驻留在单独线程(在不同处理器上执行的)中的a和b值,这是一个非常棘手的问题。
不能真正很好地保证两个线程的i值同时是相同的(毕竟,乘法和加法可能需要不同的执行次数),这意味着一个线程可能需要等待另一个线程在比较对应于依赖值i的a和b之前使它们同步。或者,我们是否为两个线程的值比较和同步创建了第三个线程?无论是哪种情况,复杂性都在快速增长,所以我认为我们可以同意,我们开始看到严重的混乱--线程之间的共享状态可能非常棘手。
因此,您提供的代码示例只可以部分并行,而无需付出很大努力,但是,一旦需要比较这两个变量,分离这两个操作就变得非常困难。
当涉及并发编程时,有几个大拇指规则:
当有一些任务可以分解为涉及处理完全独立于其他数据及其结果(状态)的数据的部分时,那么并行化就非常容易。
例如,两个函数从输入中计算一个值(以伪代码表示):
f(x) = { return 2x }
g(x) = { return x+1 }这两个函数不相互依赖,因此它们可以并行执行,而不会带来任何痛苦。此外,由于它们不是要在计算之间共享或处理的状态,因此即使需要计算x的多个值,也可以进一步拆分这些值:
x = [1, 2, 3, 4]
foreach t in x:
runInThread(f(t))
foreach t in x:
runInThread(g(t))现在,在这个例子中,我们可以让8个单独的线程执行计算。没有副作用对于并发编程来说是一件非常好的事情。
然而,一旦依赖于数据和其他计算的结果(这也意味着有副作用),并行化就变得非常困难。在许多情况下,这些类型的问题必须按顺序执行,因为它们等待其他计算的结果返回。
也许问题在于,为什么编译器不能找出可以自动并行化的部分并执行这些优化?我不是编译器方面的专家,所以我不能说,但是维基百科上有一篇关于自动再结晶的文章,其中可能包含一些信息。
发布于 2009-10-17 17:48:52
我很了解英特尔芯片。
根据您的代码,“如果(a == .\x b == .)”是一个障碍,否则处理器内核将并行执行所有代码,不管编译器做了什么样的优化。这只需要编译器不是一个非常“愚蠢”的编译器。这意味着硬件本身就有能力,而不是软件。因此,在这种情况下,线程编程或OpenMP是不必要的,尽管它们将有助于改进并行计算。注这里并不意味着超线程,只是普通的多核处理器功能。
请谷歌“处理器流水线多端口并行”来了解更多。
在这里,我想给出一个经典的例子,它可以由多核/多通道IMC平台(例如Intel Nehalem系列,如Core i7)并行执行,不需要额外的软件优化。
char buffer0[64];
char buffer1[64];
char buffer2[64];
char buffer[192];
int i;
for (i = 0; i < 64; i++) {
*(buffer + i) = *(buffer0 + i);
*(buffer + 64 + i) = *(buffer1 + i);
*(buffer + 128 + i) = *(buffer2 + i);
}为什么?三个原因。
1核心i7具有三通道IMC,其总线宽度为192位,每通道64位;存储器地址空间在每条高速缓存线的基础上交织在各通道之间。缓存行长度为64字节.因此,基本的buffer0在信道0上,buffer1在信道上,buffer2在信道2上;而对于buffer192来说,它在3个信道间交织,平均为64个/信道。IMC支持同时从多个通道加载或存储数据。这是多通道MC突发w/最大吞吐量。在下面的描述中,我将只说每个通道64个字节,比如w/ BL x8 (突发长度8,8x8= 64字节=缓存行)。
2缓冲区0..2和缓冲区在内存空间中是连续的(无论是在特定的页面上,实际上还是物理上,堆栈memroy)。当运行时,buffer0、1、2和缓冲区被加载/获取到处理器缓存中,总共有6行缓存。因此,在开始执行上面的"for(){}“代码之后,就根本不需要访问内存了,因为所有数据都在缓存、L3缓存中,这是一个非核心部分,由所有内核共享。我们这里不谈L1/2。在这种情况下,每个内核都可以获取数据,然后独立计算它们,唯一的要求是操作系统支持MP,并且允许窃取任务,比如运行时调度和亲缘共享。
3 buffer0、1、2和缓冲区之间不存在任何依赖关系,因此不存在执行延迟或障碍。例如,execute *(缓冲器+ 64 + i) = *(buffer1 + i)不需要等待*(缓冲器+ i) = *(buffer0 + i)的执行。
然而,最重要和最困难的是“窃取任务、运行时调度和亲缘共享”,这是因为对于给定的任务,只有一个任务选择上下文,所有内核都应该共享它来执行并行执行。任何能理解这一点的人都是世界上顶尖的专家之一。我正在寻找这样一个专家来合作我的开源项目,并负责并行计算和最新的HPC架构相关的工作。
注在上面的示例代码中,您还可以使用一些SIMD指令,例如movntdq/a,它将绕过处理器缓存并直接写入内存。在执行软件级优化时,这也是一个非常好的主意,尽管访问内存非常昂贵,例如,访问缓存(L1)可能只需要一个周期,但在以前的x86芯片上访问内存需要142个周期。
请访问http://effocore.googlecode.com和http://effogpled.googlecode.com以了解详细信息。
https://stackoverflow.com/questions/876859
复制相似问题