【问题标题】:Use bash wait in for-loop [duplicate]在for循环中使用bash等待[重复]
【发布时间】:2018-04-13 18:23:01
【问题描述】:

(我已经搜索并期望之前有人问过这个问题,但是尽管有很多类似的问题,但找不到类似的问题)

我希望这个 for 循环在 3 个不同的线程/进程中运行,wait 似乎是正确的命令

for file in 1.txt 2.txt 3.text 4.txt 5.txt
        do something lengthy &
        i=$((i + 1))
        wait $!
done

但我猜这个结构只是启动一个线程,然后等到它完成后再启动下一个线程。我可以将wait 放在循环之外,但我该怎么做

  1. 访问 pid?
  2. 限制为 3 个线程?

【问题讨论】:

  • 我是否理解正确,您希望在三个线程中处理五个相互独立的任务(在发生时排队),wait 的唯一目的是确保没有其他事情发生在所有五个人都退出之前?
  • 你不一定要给wait一个PID。如果您在没有参数的情况下调用wait,它将等待所有后台进程,因此将wait 放在done 之后将等待所有线程完成。不确定如何限制为 3 个线程...
  • @Dario 我有两个函数,1 和 2。1(上面的那个)可以并行化,但 2 在处理完所有 5 个文件之前不能运行。我有 4 个核心,我需要留下一个,这样其他所有东西都可以不间断地运行。如果我正确理解您的问题,则分析器是“是”,
  • 这些是进程,而不是线程。
  • bash 本身并不适合维护这样的进程池。

标签: bash shell


【解决方案1】:

jobs 内置函数可以列出当前正在运行的后台作业,因此您可以使用它来限制创建的数量。要将您的工作限制为三个,请尝试以下操作:

for file in 1.txt 2.txt 3.txt 4.txt 5.txt; do
  if [ $(jobs -r | wc -l) -ge 3 ]; then
    wait $(jobs -r -p | head -1)
  fi

  # Start a slow background job here:
  (echo Begin processing $file; sleep 10; echo Done with $file)&
done
wait # wait for the last jobs to finish

【讨论】:

  • 在您选择等待的作业完成时,可以完成多个作业。这不是让您的进程池保持忙碌的好方法。
  • (wait -n,在bash 4.3 中引入,是一种改进,因为您只需阻塞直到任意进程完成,但这并不意味着只有 i> 一个流程已完成,在您决定可以启动多少个新流程时,作业可以继续完成。)
  • 没错,尽管更重要的是,我们等待的工作实际上可能是三人中最后一个完成的工作——谁知道呢——所以它不是最佳的。正如您在问题 cmets 中所说,bash 本身并不适合管理并发。然而,考虑到 bash 原语,这是一种避免超过进程限制的相对简单的方法,即使它可能未充分利用池。
【解决方案2】:

GNU Parallel 可能值得一看。

我的第一次尝试,

parallel -j 3 'bash -c "sleep {};   echo {};"' ::: 4 1 2 5 3

根据并行发明者的说法,可以缩短为

parallel -j3 sleep {}\; echo {} ::: 4 1 2 5 3
1
2
4
3
5

并屏蔽分号,打字更友好,像这样:

parallel -j3 sleep {}";" echo {} ::: 4 1 2 5 3

也可以。

它看起来并不简单,到目前为止我只测试了 2 次,一次是为了回答这个问题。 parallel --help 显示了一个有更多信息的来源,手册页有点令人震惊。 :)

parallel -j 3 "something lengthy {}" ::: {1..5}.txt

可能会起作用,这取决于something lengthy 是一个程序(很好)还是只是 bashcode(afaik,你不能只并行调用一个 bash 函数)。

在 xUbuntu-Linux 16.04 上,并没有安装并行,而是在 repo 中。

【讨论】:

  • 第一个例子更短:parallel -j3 sleep {}\; echo {} ::: 4 1 2 5 2
  • @OleTange:您好 Ole,感谢您的平行。到目前为止,已观看了 3 或 4 个视频,教程已在 40 个选项卡之一中打开,等待我有更多时间。
【解决方案3】:

基于 Rob Davis 的回答:

#!/bin/bash
qty=3

for file in 1.txt 2.txt 3.txt 4.txt 5.txt; do
    while [ `jobs -r | wc -l` -ge $qty ]; do
        sleep 1
        # jobs #(if you want an update every second on what is running)
    done
    echo -n "Begin processing $file"
    something_lengthy  $file &
    echo $!
done
wait

【讨论】:

    【解决方案4】:

    您可以使用 subshel​​l 方法示例

     ( (sleep 10) &
        p1=$!
        (sleep 20) &
        p2=$!
        (sleep 15) &
        p3=$!
        wait
        echo "all finished ..." )
    

    注意等待调用等待子shell中的所有子shell,您可以使用带3的模运算符(%)并使用提醒检查第一个第二和第三个进程ID(如果需要),或者可以使用它来运行3个并行线程. 希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 2015-07-03
      • 2014-11-22
      • 2018-07-15
      • 2023-01-20
      • 2018-06-09
      • 2018-01-06
      • 2016-03-24
      相关资源
      最近更新 更多