使用多核与g ++进行编译


172

快速的问题:允许g ++生成自身的多个实例以便更快地编译大型项目(例如,对于多核CPU一次是4个源文件)的编译器标志是什么?


真的有帮助吗?我所有的编译作业都是I / O绑定的,而不是CPU绑定的。
Brian Knoblauch

5
即使它们是受I / O约束的,当CPU重载发生时(即使只有一个g ++实例,也会有停顿的情况),您也可以保持较高的I / O负载,并且如果调度程序有更多选择,则可能会提高I / O效率。接下来从磁盘读取什么。我的经验是,明智地使用make -j几乎总会带来一些改善。
Flexo

1
@BrianKnoblauch但是在我的机器上(真实的机器或在VirtualBox中),它受CPU限制,我发现编译时CPU通过“ top”命令处于繁忙状态。
13年

1
即使它们受I / O约束,我们也可以使用gcc的标志“ -pipe”来减轻痛苦。
2013年

刚刚在Google上看到了这一点:gcc.gnu.org/onlinedocs/libstdc++/manual/…
Jim Michaels

Answers:


238

您可以使用make-使用gnu使它成为-j标志(这在单处理器计算机上也有帮助)。

例如,如果要从make进行4个并行作业:

make -j 4

您也可以在管道中运行gcc

gcc -pipe

这将流水线化编译阶段,这也将有助于保持内核繁忙。

如果您还可以使用其他机器,则可以签出 distcc,这也会将编译出来的内容也提供给这些计算机。


35
您的-j数量应为核心数量的1.5倍。
Mark Beckwith

2
谢谢。我一直试图通过CFLAGS / CPPFLAGS / CXXFLAGS将“ -j#”传递给gcc。我完全忘记了“ -j#”是GNU make(而不是GCC)的参数。
chriv 2012年

33
为什么GNU Make 的-j选项需要是CPU内核数的1.5倍?
bitek 2012年

27
1.5号是因为注意到I / O瓶颈问题。这是一个经验法则。大约1/3的作业将等待I / O,因此其余的作业将使用可用的内核。大于内核的数字更好,甚至可以达到2倍。另请参阅:古努(Gnu)-j争辩
轻声喧noise

4
@JimMichaels可能是因为在项目中设置了严重的依赖关系(即使目标的依赖关系尚未准备好,目标也会开始构建),因此只有顺序构建才能成功。
2015年

42

没有这样的标志,并且有一个与Unix理念背道而驰的原则,即每个工具只能执行一个功能并很好地执行它。从概念上讲,生成编译器进程是构建系统的工作。您可能正在寻找的是GNU make的-j(jobs)标志,

使-j4

或者,您可以使用pmake或类似的并行make系统。



3
“ Unix pedantry没有帮助”匿名编辑器那时还不是pedantry。回滚。评论者请多注意您的工作。
Lightness Races in Orbit

12

人们提到makebjam也支持类似的概念。使用bjam -jx指示bjam建立x并发命令。

我们在Windows和Linux上使用相同的构建脚本,并且使用此选项将在两个平台上的构建时间减半。真好


9

make将为您做到这一点。研究手册页中的-j-l开关。我不认为g++是可并行化的。


+1表示提及的-l选项(除非所有先前的作业都终止,否则不会开始新的作业)。否则,似乎链接器作业并非以所有目标文件都已构建为开始(因为某些编译仍在进行中),因此链接器作业失败。
NGI

8

如果使用make,请发出-j。来自man make

  -j [jobs], --jobs[=jobs]
       Specifies the number of jobs (commands) to run simultaneously.  
       If there is more than one -j option, the last one is effective.
       If the -j option is given without an argument, make will not limit the
       number of jobs that can run simultaneously.

最值得注意的是,如果您要编写脚本或确定可用内核的数量(取决于您的环境,并且如果您在许多环境中运行,则可能会发生很大变化),则可以使用无处不在的Python函数 cpu_count()

https://docs.python.org/3/library/multiprocessing.html#multiprocessing.cpu_count

像这样:

make -j $(python3 -c 'import multiprocessing as mp; print(int(mp.cpu_count() * 1.5))')

如果您问为什么1.5我会在上面的评论中引用用户虚假噪声:

1.5的数字是由于指出的I / O绑定问题。这是一个经验法则。大约1/3的作业将等待I / O,因此其余的作业将使用可用的内核。大于核心的数字更好,甚至可以高达2倍。


5
大多数Linux用户可能更喜欢较短的代码:GNU Coreutils中的make -j`nproc` with nproc
西罗Santilli郝海东冠状病六四事件法轮功

如果您使用的是SSD,则I / O不会成为问题。只是基于Ciro的评论,您可以执行以下操作:( make -j $(( $(nproc) + 1 ))确保将空格放在我的位置)。
Ed K

nproc不可用的系统(例如在manylinux1容器中)上使用python的不错建议,它通过避免运行yum update/ 来节省更多时间yum install
骑马


3

我不确定g ++,但是如果您使用的是GNU Make,则“ make -j N”(其中N是make可以创建的线程数)将允许make同时运行多个g ++作业。因为文件不相互依赖)。


2
没有Nist不是线程数!许多人误解了这一点,但是却-j N告诉人们应该立即生成多少个进程,而不是线程。这就是为什么它不如MS cl -MT(真正的多线程)性能高的原因。
Sebi2020

2

GNU并行

我当时正在制定综合编译基准,因此不必费心编写Makefile,因此我使用了:

sudo apt-get install parallel
ls | grep -E '\.c$' | parallel -t --will-cite "gcc -c -o '{.}.o' '{}'"

说明:

  • {.} 接受输入参数并删除其扩展名
  • -t 打印出正在运行的命令,以使我们了解进度
  • --will-cite 如果您使用软件发布结果,则删除引用该软件的请求...

parallel 非常方便,我什至可以自己做一个时间戳检查:

ls | grep -E '\.c$' | parallel -t --will-cite "\
  if ! [ -f '{.}.o' ] || [ '{}' -nt '{.}.o' ]; then
    gcc -c -o '{.}.o' '{}'
  fi
"

xargs -P也可以并行运行作业,但是执行扩展操作或使用它来运行多个命令要不那么方便:通过xargs调用多个命令

在以下位置询问了并行链接:链接时gcc可以使用多个内核吗?

TODO:我想我在某处读到可以将编译简化为矩阵乘法,因此也许还可以加快大文件的单文件编译速度。但是我现在找不到参考。

已在Ubuntu 18.10中测试。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.