如何在多核心上运行与Bash管道相关的进程?

11

我有一个简单的bash脚本,将一个进程的输出管道传递给另一个进程。即:

dostuff | filterstuff

我在我的Linux系统(如果有影响,是openSUSE,内核2.6.27)上发现这两个进程都运行在同一个核心上。然而,在不同的核心上运行不同的进程是一种默认策略,在这种情况下没有触发。

系统的哪个组件负责此事,我该怎么做才能利用多核功能?

请注意,在2.6.30内核上不存在此问题。

澄清:根据Dennis Williamson的建议,我使用top程序确保管道进程确实始终在同一个处理器上运行。通常表现得很好的Linux调度程序这次没有做到。

我想bash中的某些内容防止操作系统这样做。问题是我需要一个适用于多核和单核机器的可移植解决方案。Dennis Williamson提出的taskset solution在单核机器上无法工作。目前我正在使用:

dostuff | taskset -c 0 filterstuff 

但这似乎是一种不太优雅的解决方案。是否有更好的解决方案?


尝试不使用taskset,用top重复运行测试几次。当我这样做时,有时两个进程在同一个CPU上,有时在不同的CPU上。 - Dennis Williamson
1
尝试使用 ( dostuff ) | ( filterstuff ) 并查看它们出现在哪个核心上。一个区别(如果有影响的话)是你在多核系统上,而我在多处理器(每个单核)系统上。无论如何,为什么要分离这些进程呢?它们是你编写的程序吗?你能否更改它们以便它们自己影响调度程序? - Dennis Williamson
1
@Jeremy:是的,它在不同核心上运行2-3倍快:我是通过bzcat file.bz2 | gzip >file.gz来测量的。在原始情况下,dostuff执行昂贵的计算并产生大量输出,而filterstuff则实时进行归档。在我的情况下,数据传输不是瓶颈。 - P Shved
@Pavel Shved:请看我编辑过的帖子,里面有一个你可以尝试的实验。 - Dennis Williamson
@Novelocrat 这个问题应该在 LKML 上讨论,还是说 bash 可以在没有内核帮助的情况下执行启发式算法? - Jeremy Powell
显示剩余3条评论
3个回答

7

尝试以下方法来设置CPU(处理器)亲和性:

taskset -c 0 dostuff | taskset -c 1 filterstuff

编辑:

尝试这个实验:

  • create a file called proctest and chmod +x proctest with this as the contents:

    #!/bin/bash
    while true
    do
      ps
      sleep 2
    done  
    
  • start this running:

    ./proctest | grep bash
    
  • in another terminal, start top - make sure it's sorting by %CPU
  • let it settle for several seconds, then quit
  • issue the command ps u
  • start top -p with a list of the PIDs of the highest several processes, say 8 of them, from the list left on-screen by the exited top plus the ones for proctest and grep which were listed by ps - all separated by commas, like so (the order doesn't matter):

    top -p 1234, 1255, 1211, 1212, 1270, 1275, 1261, 1250, 16521, 16522
    
  • add the processor field - press f then j then Space
  • set the sort to PID - press Shift+F then a then Space
  • optional: press Shift+H to turn on thread view
  • optional: press d and type .09 and press Enter to set a short delay time
  • now watch as processes move from processor to processor, you should see proctest and grep bounce around, sometimes on the same processor, sometimes on different ones

太棒了!它能正常工作。但是,嗯,为什么我不能避免手动分配到核心呢? - P Shved
2
请参阅 man sched_setschedulerman cpuset 以获取更多信息。Linux 在调度方面做得很好。尝试运行 top 并按 fj<space> 添加处理器(P)字段,您会发现不同的进程正在不同的 CPU 上运行。 - Dennis Williamson
您还可以在 top 中按下 1(数字一)以查看每个 CPU 的单独 CPU 负载。 - Dennis Williamson

7
假设dostuff正在一个CPU上运行。它将数据写入管道,该数据将在该CPU的缓存中。由于filterstuff正在从该管道读取数据,调度程序决定在同一CPU上运行它,以便其输入数据已经在缓存中。
如果您的内核使用CONFIG_SCHED_DEBUG=y构建,
# echo NO_SYNC_WAKEUPS > /sys/kernel/debug/sched_features
应该禁用此类启发式算法。(有关其他调度程序可调整项,请参见/usr/src/linux/kernel/sched_features.h/proc/sys/kernel/sched_*。)
如果这有所帮助,并且问题仍然存在于更新的内核中,并且在单个CPU上运行确实比在单个CPU上运行更快,请向Linux内核邮件列表报告问题,以便他们可以调整其启发式算法。

NO_SYNC_WAKEUPS 已经生效。然而,内核版本为2.6.27,在2.6.30系统上似乎没有出现这个问题。我会进一步调查。 - P Shved
无法在2.6.30上重现。进程在有和没有SYNC_WAKEUPS的情况下都会在核心之间反弹。 - P Shved
好的,我认为这解决了问题。由于我的产品没有很多用户,并且他们的内核编译得很好,我可以要求他们按照您提供的方式进行调整。谢谢。 - P Shved

1
Linux调度程序旨在提供最大吞吐量,而不是做你认为最好的事情。如果您运行与管道连接的进程,则很可能其中一个会阻塞另一个,然后它们交换位置。将它们分别运行在不同的核心上几乎没有任何作用,因此不会这样做。
如果您有两个任务都真正准备好在CPU上运行,我希望看到它们在不同的核心上安排(在某个时候)。
我的猜测是,dostuff运行直到管道缓冲区变满,此时它无法再运行,因此“filterstuff”进程运行,但它运行的时间非常短,以至于dostuff直到filterstuff完成过滤整个管道缓冲区后才重新安排。

你的猜测是错误的。进程运行方式如下:dostuff 占用核心 CPU 时间的 60%,而 filterstuff 占用剩余的 40%。它们在运行几分钟内不会被重新调度到不同的核心上。 - P Shved
好的,那就只是一个想法。 - MarkR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接