信号量式结构是否有任何方式/二进制?例如。为了在我们遍历文件目录时运行固定数量的(后台)子流程(在这里使用单词“ sub-process”而不是“ thread”,因为在我的bash命令中使用附加的&
“多线程”(但可以接受任何更方便的建议)。
我的实际用例是尝试在CentOS 7上使用名为bcp
的二进制文件将一组(可变大小的)TSV文件写入远程MSSQL Server DB,并且观察到似乎存在问题。运行太多线程时的程序。例如。像
for filename in $DATAFILES/$TARGET_GLOB; do
if [ ! -f $filename ]; then
echo -e "\nFile $filename not found!\nExiting..."
exit 255
else
echo -e "\nImporting $filename data to $DB/$TABLE"
fi
echo -e "\nStarting BCP export threads for $filename"
/opt/mssql-tools/bin/bcp "$TABLE" in "$filename" \
$TO_SERVER_ODBCDSN \
-U $USER -P $PASSWORD \
-d $DB \
$RECOMMEDED_IMPORT_MODE \
-t "\t" \
-e ${filename}.bcperror.log &
done
# collect all subprocesses at the end
wait
以不受限制的方式立即为每个文件所有启动一个新子流程的
似乎崩溃了每个子流程。希望查看是否在循环中添加类似信号量的结构以锁定将被旋转的子进程数量会有所帮助。例如。诸如此类(在此处使用一些非bash类的伪代码)
sem = Semaphore(locks=5)
for filename in $DATAFILES/$TARGET_GLOB; do
if [ ! -f $filename ]; then
echo -e "\nFile $filename not found!\nExiting..."
exit 255
else
echo -e "\nImporting $filename data to $DB/$TABLE"
fi
sem.lock()
<same code from original loop>
sem.unlock()
done
# collect all subprocesses at the end
wait
如果这样的事情是可能的,或者如果这是现有最佳实践解决方案的常见问题(对于bash编程我还是很陌生),建议将不胜感激。
答案 0 :(得分:1)
遵循@Mark Setchell的建议,使用GNU Parallel将循环(在模拟cron环境中(请参见https://stackoverflow.com/a/2546509/8236733)替换为
bcpexport() {
filename=$1
TO_SERVER_ODBCDSN=$2
DB=$3
TABLE=$4
USER=$5
PASSWORD=$6
RECOMMEDED_IMPORT_MODE=$7
DELIMITER=$8 # DO NOT use format like "'\t'", nested quotes seem to cause hard-to-catch error
<same code from original loop>
}
export -f bcpexport
parallel -j 10 bcpexport \
::: $DATAFILES/$TARGET_GLOB \
::: "$TO_SERVER_ODBCDSN" \
::: $DB \
::: $TABLE \
::: $USER \
::: $PASSWORD \
::: $RECOMMEDED_IMPORT_MODE \
::: $DELIMITER
一次最多可运行10个线程,其中$DATAFILES/$TARGET_GLOB
是全局字符串,用于返回所需目录中的所有文件。 (例如,“ $ storagedir / tsv / *。tsv”)(并将剩余的固定参数与该glob返回的每个元素相加,作为所示的剩余并行输入)($TO_SERVER_ODBCDSN
变量实际上是“ -D -S <some ODBC DSN>
”,因此需要添加引号以作为单个arg传递。因此,如果$DATAFILES/$TARGET_GLOB
全局文件返回文件A,B,C ...,我们最终将运行命令
bcpexport A "$TO_SERVER_ODBCDSN" $DB ...
bcpexport B "$TO_SERVER_ODBCDSN" $DB ...
bcpexport C "$TO_SERVER_ODBCDSN" $DB ...
...
并行。
是使用parallel
的另一个好处。
GNU并行确保命令的输出与顺序运行命令所获得的输出相同。
答案 1 :(得分:0)
使用&
示例代码
#!/bin/bash
xmms2 play &
sleep 5
xmms2 next &
sleep 1
xmms2 stop
答案 2 :(得分:0)
这并不完全等效,但是您可以使用xargs
一次启动给定数量的进程:
-P max-procs, --max-procs=max-procs
Run up to max-procs processes at a time; the default is 1. If
max-procs is 0, xargs will run as many processes as possible at
a time. Use the -n option or the -L option with -P; otherwise
chances are that only one exec will be done. While xargs is
running, you can send its process a SIGUSR1 signal to increase
the number of commands to run simultaneously, or a SIGUSR2 to
decrease the number. You cannot decrease it below 1. xargs
never terminates its commands; when asked to decrease, it merely
waits for more than one existing command to terminate before
starting another.
类似的东西:
printf "%s\n" $DATAFILES/$TARGET_GLOB |
xargs -d '\n' -I {} --max-procs=5 bash -c '
filename=$1
if [ ! -f $filename ]; then
echo -e "\nFile $filename not found!\nExiting..."
exit 255
else
echo -e "\nImporting $filename data to $DB/$TABLE"
fi
echo -e "\nStarting BCP export threads for $filename"
/opt/mssql-tools/bin/bcp "$TABLE" in "$filename" \
$TO_SERVER_ODBCDSN \
-U $USER -P $PASSWORD \
-d $DB \
$RECOMMEDED_IMPORT_MODE \
-t "\t" \
-e ${filename}.bcperror.log
' _ {}
您需要预先导出TABLE
,TO_SERVER_ODBCDSN
,USER
,PASSWORD
,DB
和RECOMMEDED_IMPORT_MODE
变量,以便它们在xargs
开始的过程中可用。或者,您可以在此处将使用bash -c
运行的命令放在单独的脚本中,然后将变量放入该脚本中。