Bash循环和线程化

10
我有一个while循环从$hosts读取行。
while read line
do
    ip=$line
    check
done < $hosts

我的问题是,我是否可以使用某种方法加快速度,或者一次在10个主机上运行检查,每次检查都在不同的IP上,并在所有$host中的IP都被检查后结束? 谢谢。


1
严格来说,Bash 没有访问线程的能力。后台作业运行在一个单独的进程中,而不是线程中。因此,严格来说,这是多进程而不是多线程。 - tripleee
3个回答

22
你可以通过 & 将任务发送到后台。 如果你想等待它们全部完成,可以使用 wait 命令:
process_to_background &
echo Processing ...
wait
echo Done

如果您想等待一个(或少量)特定的任务,请获取在后台启动给定任务的pid

important_process_to_background &
important_pid=$!
while i in {1..10}; do
    less_important_process_to_background $i &
done

wait $important_pid
echo Important task finished

wait
echo All tasks finished

需要注意的是:后台进程可能会打乱输出,因为它们将异步运行。您可以使用命名管道来收集它们的输出。

编辑

正如评论中所要求的,可能需要限制fork的后台进程数量。在这种情况下,您可以跟踪已启动的后台进程数量,并通过命名管道与它们通信。

mkfifo tmp # creating named pipe

counter=0
while read ip
do
  if [ $counter -lt 10 ]; then # we are under the limit
    { check $ip; echo 'done' > tmp; } &
    let $[counter++];
  else
    read x < tmp # waiting for a process to finish
    { check $ip; echo 'done' > tmp; } &
  fi
done
cat /tmp > /dev/null # let all the background processes end

rm tmp # remove fifo

这个循环会遍历$hosts中的每个主机吗?即使超过10个?我不想启动超过10个进程,否则可能会占用太多资源。 - radman
这只是一个示例,展示了如何使用后台进程以及如何等待它们。如果您想指定最大线程数,那听起来像是一个线程池。我添加了一个示例,但可能不是最佳实现。 - fejese
计数器何时被减少? - Interlated
每次读取一行时,它会递减。Echo 也会打印新行。 - Interlated
2
在@Interlated,我们从不减少计数器:计数器用于初始化数量有限的“池”背景进程,然后每当先前启动的后台进程完成时,如果仍然需要,我们就会创建一个新的后台进程。 - fejese

6
您可以启动多个进程,每个进程调用函数check,并等待它们完成。
while read line 
do 
  ip=$line
  check &
done < $hosts
wait # wait for all child processes to finish

无论是否提高速度都取决于可用的处理器和函数check的实现。您必须确保在迭代之间check没有数据依赖性。

5

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