我的理解是 -X 选项应该在作业之间均匀分配参数。然而,我得到的分布非常不均匀:
user@host:/tmp/ptest$ count() {
> echo $#
> }
user@host:/tmp/ptest$ export -f count
user@host:/tmp/ptest$ count *.jpg
5825
user@host:/tmp/ptest$ parallel -X count ::: *.jpg
5039
197
197
197
195
有趣的是,仅使用文件的子集会导致参数均匀分布:
user@host:/tmp/ptest$ count p129*.jpg
975
user@host:/tmp/ptest$ parallel -X count ::: p129*.jpg
244
244
244
243
user@host:/tmp/ptest$ count p12*.jpg
4007
user@host:/tmp/ptest$ parallel -X count ::: p12*.jpg
1002
1002
1002
1001
user@host:/tmp/ptest$ count p13*.jpg
1818
user@host:/tmp/ptest$ parallel -X count ::: p13*.jpg
455
455
455
453
为什么第一种情况是错误的以及我该如何修复它?
答案1
-X
当到达 EOF 时均匀分布。
因此,在您的情况下,它会填满一个完整命令行的缓冲区(5039 个名称)并启动它。然后它会读取另外 800 个名称,直到到达 EOF。这不足以启动一个完整的作业,因此这些名称会分布在作业槽中。
参见第 37 页https://zenodo.org/record/1146014
这样做是为了避免必须提前阅读所有工作,因为并非所有工作都可用(想想tail -f file.names | parallel ...
)。
如果 GNU Parallel 在开始下一个作业之前读取足够多的名称以填满所有作业槽-X
,那么它可能是一个更好的主意,这样它就可以更早地检测到 EOF。然而,这尚未实现。欢迎补丁。
解决方法是使用:
ls *.jpg |
parallel --round --pipe -N1 parallel -Xj1 count
它不能在每次作业后输出,但可以进行行缓冲输出:
ls *.jpg |
parallel --lb --round --pipe -N1 parallel --lb -Xj1 count
如果文件名包含\n:
printf '%s\0' *.jpg |
parallel --recend '\0' --round --lb --pipe -N1 parallel -0Xj1 count