问题 如何在多个核心上运行使用bash传输的进程?


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

dostuff | filterstuff

碰巧在我的Linux系统上(openSUSE,如果它很重要,内核2.6.27),这两个进程都在一个核心上运行。但是,跑步不同 流程 在不同的核心上是默认策略,在这种情况下不会触发。

系统的哪个部分负责这个以及我应该怎样做才能利用多核功能?

注意 在2.6.30内核上没有这样的问题。

澄清:跟着 丹尼斯威廉姆森我的建议,我做了 当然 顶级程序,管道进程确实如此 总是 在同一处理器上运行。 Linux调度程序,通常做得非常好,这次不做。

我认为bash中的某些内容会阻止操作系统执行此操作。问题是我需要一个 手提 多核和单核机器的解决方案。该 taskset   由...提出 丹尼斯威廉姆森 不适用于单核机器。目前我正在使用:,

dostuff | taskset -c 0 filterstuff 

但这似乎是一个肮脏的黑客。谁能提供更好的解决方案?


6632
2017-09-09 09:39


起源

尝试重复测试 top 几次(没有 taskset)。当我这样做时,有时两个进程在同一个CPU上,有时是不同的。 - Dennis Williamson
他们总是在同一个,只利用系统的50%:( - P Shved
尝试 ( dostuff ) | ( filterstuff ) 并看看他们出现在哪个核心。一个区别(如果它很重要)是你在一个多核系统上,我在一个多处理器(每个单核)系统。你为什么要分开这些过程呢?它们是您编写的程序,是否可以更改它们以便它们自己影响调度程序? - Dennis Williamson
如果它们是串行的(unix管道的性质),如果它们位于不同的内核上,你真的可以获得性能提升吗? - Jeremy Powell
@Jeremy:是的,它在不同核心上的运行速度提高了2-3倍:我测量了这个 bzcat file.bz2 | gzip >file.gz。在原始情况下, dostuff 执行昂贵的计算并产生大量的输出和 filterstuff 将其归档。在我的情况下,数据传输不是瓶颈。 - P Shved


答案:


假设 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内核邮件列表,以便他们可以调整他们的启发式。


7
2017-09-09 19:45



NO_SYNC_WAKEUPS有效。但是,内核是2.6.27,而在2.6.30系统上似乎没有出现问题。我会进一步调查。 - P Shved
无法在2.6.30上重现它。使用和不使用SYNC_WAKEUPS时,进程在核心之间跳转。 - P Shved
好吧,我知道,这解决了这个问题。由于我的产品没有很多用户,并且他们的内核编译得很好,我可以让他们按照你提供的方式调整它们。谢谢。 - P Shved


尝试设置CPU(处理器)亲缘关系:

taskset -c 0 dostuff | taskset -c 1 filterstuff

编辑:

试试这个实验:

  • 创建一个名为proctest和的文件 chmod +x proctest 以此为内容:

    #!/bin/bash
    while true
    do
      ps
      sleep 2
    done  
    
  • 开始这个运行:

    ./proctest | grep bash
    
  • 在另一个终端,开始顶部 - 确保它按%CPU排序
  • 让它稳定几秒钟,然后退出
  • 发出命令 ps u
  • 开始 top -p 从退出的屏幕上留下的列表中列出最高几个进程的PID,例如其中的8个 top 加上那些 proctest 和 grep 被列出的 ps  - 所有以逗号分隔,如此(顺序无关紧要):

    top -p 1234, 1255, 1211, 1212, 1270, 1275, 1261, 1250, 16521, 16522
    
  • 添加处理器字段 - 按 F 然后 Ĵ 然后 空间
  • 将排序设置为PID - 按 转移+F 然后 一个 然后 空间
  • 可选:按 转移+H 打开线程视图
  • 可选:按 d 和类型 .09 并按 输入 设置一个短的延迟时间
  • 现在看着流程从处理器移动到处理器,你应该看到 proctest 和 grep 弹跳,有时在同一个处理器上,有时在不同的处理器上

7
2017-09-09 09:53



惊人!有用。但是,嗯,为什么我不能避免手动分配到核心? - P Shved
看到 man sched_setscheduler 和 man cpuset 了解更多信息。 Linux在调度方面做得很好。试试跑步 top 并按fj <space>添加处理器(P)字段,您将看到不同的进程在不同的CPU上运行。 - Dennis Williamson
你也可以按 1 (一)在 top 在顶部按CPU分别查看CPU负载。 - Dennis Williamson
@DennisWilliamson O你摇滚!!!!!!! - Theodore R. Smith


Linux调度程序旨在提供最大吞吐量,而不是您想象的最佳。如果您正在运行与管道连接的进程,很可能其中一个阻塞另一个进程,那么它们会进行交换。在不同的核心上运行它们将获得很少或没有,所以它没有。

如果你有两个真正准备在CPU上运行的任务,我希望看到它们安排在不同的核心上(在某些时候)。

我的猜测是,发生的是dostuff运行直到管道缓冲区变满,此时它不再运行,所以“filterstuff”进程运行,但它运行的时间很短,dostuff没有得到重新安排,直到filterstuff完成过滤整个管道缓冲区,然后再次调度dostuff。


1
2017-09-09 21:46



你的猜测是错的。进程如下运行: dostuff 占用核心CPU时间的60% filterstuff 占剩余的40%。并且他们不会在几分钟的运行时被重新安排到不同的核心。 - P Shved
那么公平,只是一个想法。 - MarkR