【发布时间】:2018-11-22 11:40:43
【问题描述】:
我有一个处理多年数据的 bash 脚本,因此该脚本可能需要一周时间才能完成。 为了加快这个过程,我使用多线程,通过并行运行多个实例(每个实例 = 1 天的数据)。每个实例占用 1 个 CPU,因此我可以运行尽可能多的可用 CPU 实例。当我在与他人共享的强大服务器中运行该进程时,有时我可能会有更多或更少的 CPU 可用。 我当前的脚本是:
#!/bin/bash
function waitpid {
#Gather the gLABs PID background processes (Maximum processes in
#background as number of CPUs)
NUMPIDS=`jobs -p|awk 'END {print NR}'`
#A while is set because there seems to be a bug in bash that makes
#sometimes the "wait -n" command
#exit even if none of provided PIDs have finished. If this happens,
#the while loops forces the
#script to wait until one of the processes is truly finished
while [ ${NUMPIDS} -ge ${NUMCPUS} ]
do
#Wait for gLAB processes to finish
PIDS="`jobs -p|awk -v ORS=" " '{print}'`"
wait -n ${PIDS} >/dev/null 2>/dev/null
NUMPIDS=`jobs -p|awk 'END {print NR}'`
done
}
NUMPCUS=10
for(...) #Loop for each day
do
day=... #Set current day variable
#Command to execute, put in background
gLAB_linux -input ${day}folder/${day}.input -output ${day)outfolder/${day}.output &
#Wait for any process to finish if NUMCPUS number of processes are running in background
waitpid
done
因此,我的问题是:如果此脚本正在运行,有什么方法可以在不停止脚本的情况下将变量 NUMCPUS 更改为任何值(例如 NUMCPUS=23)? 如果可能,我更喜欢不涉及读取或写入文件的方法(如果可能,我希望将临时文件减少到 0)。 我不介意这是否是一个“hackish”过程,例如this answer 中描述的方法。实际上,我在 gdb 中尝试了与该答案中类似的命令,但没有成功,我在 gdb 中出现以下错误(并且还导致进程崩溃):
(gdb) attach 23865
(gdb) call bind_variable("NUMCPUS",11,0)
'bind_variable' has unknown return type; cast the call to its declared return type
(gdb) call (int)bind_variable("NUMCPUS",11,0)
Program received signal SIGSEGV, Segmentation fault
EDIT1:脚本的一些 cmets:
- gLAB_linux 是一个单核处理程序,不知道 NUMCPUS 变量
- 每次 gLAB_linux 执行大约需要 5 个小时才能完成,因此 bash 脚本大部分时间都在
wait -n内休眠。 - NUMCPUS 必须是脚本的局部变量,因为可能有另一个类似这样的脚本并行运行(仅更改提供给 gLAB_linux 的参数)。因此 NUMCPUS 不能是环境变量。
- 访问 NUMCPUS 的唯一进程是 bash 脚本
EDIT2:@Kamil 回答后,我添加了从文件中读取 CPU 数量的建议
function waitpid {
#Look if there is a file with new number of CPUs
if [ -s "/tmp/numCPUs_$$.txt" ]
then
TMPVAR=$(awk '$1>0 {print "%d",$1} {exit}' "/tmp/numCPUs_$$.txt")
if [ -n "${TMPVAR}" ]
then
NUMCPUS=${TMPVAR}
echo "NUMCPUS=${TMPVAR}"
fi
rm -f "/tmp/numCPUs_$$.txt"
fi
#Gather the gLABs PID background processes (Maximum processes in
#background as number of CPUs)
NUMPIDS=`jobs -p|awk 'END {print NR}'`
#A while is set because there seems to be a bug in bash that makes
#sometimes the "wait -n" command
#exit even if none of provided PIDs have finished. If this happens,
#the while loops forces the
#script to wait until one of the processes is truly finished
while [ ${NUMPIDS} -ge ${NUMCPUS} ]
do
#Wait for gLAB processes to finish
PIDS="`jobs -p|awk -v ORS=" " '{print}'`"
wait -n ${PIDS} >/dev/null 2>/dev/null
NUMPIDS=`jobs -p|awk 'END {print NR}'`
done
}
【问题讨论】:
-
查看GNU parallel 的
--limit参数。 -
用信号控制怎么样?
-
每个实例会有不同的输入输出文件和文件夹,所以我不能使用并行bash命令。我编辑了这个问题。使用信号,问题是我不能为变量设置任意值
-
@AwkMan 从文件中读取变量比使用 gdb 破解要可靠得多,但我猜你这样做是为了好玩,而不是祝你好运! btw
parallel可以从标准输入读取 cmd 行。 -
@AwkMan 并行支持从文件中读取 proc num。