同时启动两个过程,并从早些时候完成的过程中收集结果



假设我想运行两个命令c1c2,它们基本上是在Linux上处理(但不修改)同一片段的数据。

现在,我想同时启动它们,看看哪个过程更快,一旦一个进程完成,我将收集其输出(可以将其借入使用c1 >> log1.txt的文件中),然后终止另一个过程。

请注意,两个过程的处理时间可能在很大程度上有所不同,因此可以观察到,例如一个过程需要十秒钟,而另一个则需要60秒。

======================

我尝试了以下脚本集,但它会在我的计算机上引起无限循环:

import os

os.system("./launch.sh")

launch.sh

#!/usr/bin/env bash
rm /tmp/smack-checker2
mkfifo /tmp/smack-checker2
setsid bash -c "./sleep60.sh ; echo 1 > /tmp/run-checker2" &
pid0=$!
setsid bash -c "./sleep10.sh ; echo 2 > /tmp/run-checker2" &
pid1=$!
read line </tmp/smack-checker2
printf "Process %d finished earliern" "$line"
rm /tmp/smack-checker2
eval kill  -- -$"pid$((line ^ 1))"

sleep60.sh

#!/usr/bin/env bash
sleep 60

sleep10.sh

#!/usr/bin/env bash
sleep 10

使用wait -n等待任何一个进程退出。忽略比赛条件和PID编号包装,

c1 & P1=$!
c2 & P2=$!
wait -n  # wait for either one to exit
if ! kill $P1; then
  # failure to kill $P1 indicates c1 finished first
  kill $P2
  # collect c1 results...
else
  # c2 finished first
  kill $P1
  # collect c2 results...
fi

有关文档。

请参阅help waitman bash

我将运行2个进程并将其写入共享的命名管道完成后。从命名管中读取是一个阻塞操作因此,您不需要有趣的sleep指令。它会是:

#!/usr/bin/env bash
mkfifo /tmp/run-checker
(./sleep60.sh ; echo 0 > /tmp/run-checker) &
(./sleep10.sh ; echo 1 > /tmp/run-checker) &
read line </tmp/run-checker
printf "Process %d finished earliern" "$line"
rm /tmp/run-checker
kill -- -$$

Sleep60.sh:

#!/usr/bin/env bash
sleep 60

sleep10.sh:

#!/usr/bin/env bash
sleep 10

编辑:

如果您要像这样调用脚本表单python脚本:

#!/usr/bin/env python3
import os
os.system("./parallel.sh")
print("Done")

您会得到:

Process 1 finished earlier
./parallel.sh: line 11: kill: (-13807) - No such process
Done

这是因为kill -- -$$试图将术语信号发送到该过程man 1 kill中指定的组:

-n

其中n大于1。过程组n中的所有过程均为 发出信号。当给出" -n"的论点时, 是为了表示过程组,要么信号必须是 首先指定,否则该论点必须先于a- 选项,否则将其作为发送的信号。

从终端运行并行运行时,它可以正常工作,因为$$是一个子壳以及过程组的PID。我用它是因为杀死Parallel.SH,Process0或Process1以及所有他们的孩子一枪。但是,当parallel.sh从Python脚本$$不再表示过程组和kill --失败。

您可以像这样修改并行修改:

#!/usr/bin/env bash
mkfifo /tmp/run-checker
setsid bash -c "./sleep60.sh ; echo 0 > /tmp/run-checker" &
pid0=$!
setsid bash -c "./sleep10.sh ; echo 1 > /tmp/run-checker" &
pid1=$!
read line </tmp/run-checker
printf "Process %d finished earliern" "$line"
rm /tmp/run-checker
eval kill  -- -$"pid$((line ^ 1))"

现在,当从Python脚本调用时,它也将起作用。最后一行

eval kill  -- -$"pid$((line ^ 1))"

如果PID1较早完成或PID1,则杀死PID0,如果PID1较早完成使用 ^二进制操作员将0转换为1,反之亦然。如果你不喜欢它,您可以使用更多的详细表格:

if [ "$line" -eq "$pid0" ]
then
    echo kill  "$pid1"
    kill  -- -"$pid1"
else
    echo kill  "$pid0"
    kill -- -"$pid0"
fi

这个片段可以给您一些想法吗?

#!/bin/sh
runproc1() {
  sleep 5
  touch proc1    # file created when terminated
  exit
}
runproc2() {
  sleep 10
  touch proc2    # file created when terminated
  exit
}
# remove flags
rm proc1
rm proc2
# run processes concurrently
runproc1 &
runproc2 &
# wait until one of them is finished
while [ ! -f proc1 -a ! -f proc2 ]; do
  sleep 1
  echo -n "."
done

这个想法是将两个过程包装到两个函数中,最后,触摸文件以发出终止计算的信号。删除用作标志的文件后,该功能在后台执行。最后一步是注意任何一个文件显示。那时,可以做任何事情:继续等待另一个过程,或杀死它。

启动此精确的脚本,大约需要5秒钟,然后终止。我看到文件" proc1"是创建的,没有proc2。几秒钟后(确切地说是5个),也创建了" proc2"。这意味着即使脚本终止,任何未完成的工作都可以继续运行。

相关内容

最新更新