如何限制通过gnu并行启动的每个python进程使用一个CPU?

问题描述

如果我运行此脚本

$ seq 1 4 | taskset -c 0-3 parallel -j4 -u <my_bash_script.sh>

然后<my_bash_script.sh>中包含的每个python进程都在多个cpus上运行,而不是一个。 python函数同时使用numpy和pytorch。因此,选项taskset -c 0-4强加了cpu的最大数量,但不能保证每个进程都限于一个cpu

我尝试过

$ export OPENBLAS_NUM_THREADS=1
$ export MKL_NUM_THREADS=1

但是没有用

我还添加了python脚本

import mkl
mkl.set_num_threads(1)

但没有帮助

解决方法

使用作业位:

$ seq 1 4 | parallel -j4 -u taskset -c {%} <my_bash_script.sh>

Jobslot是为此而构建的:假设您有4个以上的工作。如果您随后将每4个工作分配给cpu 4,则您可能会冒险每4个工作要短于其他工作。在这种情况下,即使还有更多作业要运行,CPU 4也会处于空闲状态。

Jobslot不会将每第4个作业传递给cpu4。相反,它看起来是哪个cpu(或更确切地说是jobslot)完成了一个作业,然后在该cpu上开始了一个新作业。

(此外:由于您使用的是-u,因此您应该了解--group(默认值)和--linebuffer(通常是使用-u时真正想要的)之间的区别))。

,

问题是您的taskset限制了parallel可以在4个CPU上运行的CPU。我非常确定parallel的子进程,my_bash_script.sh的每个实例以及它启动的Python进程也将继承同一组CPU关联,因此它们也将能够在以下任何一个上运行您指定的4个CPU。

我想,您希望将parallel开始的每个Python进程限制为不同的CPU,您可以通过将taskset移到my_bash_script.sh来实现。具体来说,不限制parallel的运行位置,而 do 限制其启动的Python进程可以通过使用{{将对调用python的调用包装在my_bash_script.sh中来运行1}}。您正在向每个对taskset的调用传递一个数字,因此您可以使用该数字为每个my_bash_script.sh的调用计算一个不同的CPU(当前您可以使用python,因为您要传递值1-4,但是如果您有更多,则想取值mod 4或其他值。)

请注意,我所描述的内容应该可以工作,但这并不完美。假设您在CPU 1上运行了进程1,在CPU 2上运行了进程2,依此类推。如果进程1首先完成,那么什么都没有使用CPU 1,也没有什么,因为您已将其他每个CPU限制为1个。理想情况下,您希望他们能够接管现在空闲的CPU,但这更加复杂。

编辑:@Ole Tang在上面的回答中建议使用(($1 - 1))来使用作业位,而不是根据您提交任务的顺序将任务分配给CPU,这有助于(但不能消除)我上述的问题。 / p>

我想知道为什么要将它们限制为每个CPU 1个。的确,如果一次运行许多内核,内核将尝试对它们进行时间切片以为每个线程分配相等的资源,并且由于上下文切换,缓存冲突等原因,这实际上可能会损害性能。OTOH,如上所述,至少在某些时候,很可能有一些CPU处于闲置状态(这并不明显),最终将为您带来更好的性能。