我有数百个文件需要处理,但只想一次运行 10 个进程。假设“doSomething”过程需要 20 秒才能完成。以下内容有效,但几乎同时启动 10 个进程。大约 20 秒后,第一组 10 组完成,下一组 10 组几乎同时开始,并且该系列重复进行。我怎样才能错开开始而不是同时发生?
find ./someFiles* | xargs --max-args=1 --max-procs=10 ./doSomething
我希望进程至少间隔 2 秒启动,而不是几乎同时启动 10 秒。
答案1
因此这样做是为了避免多个实例同时启动时磁盘/网络或其他资源使用量激增。至少对于其中的前 N 个,您需要一个固定的 X 秒间隔。
一个简单的解决方法是插入一个附加值xargs
来延迟参数。像这样:
find . -type f -print0 |
xargs -0 -n1 -P1 sh -c 'sleep 2; printf "%s\0" "$0"' |
xargs -0 -n1 -P4 sh do_something.sh
在上面我有 N=4 和间隔 2 秒。对于前 N 个参数,它将保留间隔。然后,如果某些执行接近结束,它可以及时启动更接近的执行,这就是您对此的请求评论。
我还假设执行时间不会很短,而是几秒钟或更长。如果您仍然看到下一次执行的峰值,您还可以设置稍高的延迟。避免了开始时的主要瓶颈。
测试
这是一些基本测试。处理脚本do_something.sh
随机花费 10 到 20 秒的时间。
> cat do_something.sh
printf "%s START processing %s\n" "$(date +"%H:%M:%S")" "$1"
sleep $(shuf -i10-20 -n1)
printf "%s END processing %s\n" "$(date +"%H:%M:%S")" "$1"
> touch file{1..10}
> find . -type f -name 'file*' -print0 |
> xargs -0 -n1 -P1 sh -c 'sleep 2; printf "%s\0" "$0"' |
> xargs -0 -n1 -P4 sh do_something.sh
02:03:22 START processing ./file6
02:03:24 START processing ./file9
02:03:26 START processing ./file8
02:03:28 START processing ./file2
02:03:38 END processing ./file8
02:03:38 START processing ./file7
02:03:40 END processing ./file6
02:03:40 START processing ./file1
02:03:41 END processing ./file9
02:03:41 START processing ./file3
02:03:45 END processing ./file2
02:03:45 START processing ./file4
02:03:55 END processing ./file3
02:03:55 END processing ./file7
02:03:55 START processing ./file10
02:03:55 START processing ./file5
02:04:00 END processing ./file1
02:04:02 END processing ./file4
02:04:05 END processing ./file10
02:04:13 END processing ./file5
答案2
假设它是某种 shell 脚本,请将其放在顶部:
export MYPID=$$
(
flock 9
mkdir -p .started-pids
find .started-pids/ -type f ! -newermt '-2 seconds' -delete
n=`find .started-pids/ -type f | wc -l`
sleep $n
sleep $n
touch .started-pids/$MYPID
) 9> .lockfile
它不是相当准确——有时会延迟一点更多的比应该的多,但不能少,这样你的峰值就不会发生。
当然,将锁定文件和 pid 计数目录名称更改为您喜欢的任何名称。