需要专家对以下比较提出建议:
使用循环的代码段:
for file in `cat large_file_list`
do
gzip -d $file
done
使用简单扩展的代码段:
gzip -d `cat large_file_list`
哪一个会更快?必须操作大数据集。
答案1
并发症
以下仅有时有效:
gzip -d `cat large_file_list`
三个问题是(在bash
大多数其他类似 Bourne 的 shell 中):
如果任何文件名中包含空格制表符或换行符(假设
$IFS
尚未修改),它将失败。这是因为外壳的分词。如果任何文件名中包含全局活动字符,它也可能会失败。这是因为 shell 将应用路径名扩展到文件列表。
如果文件名以 开头
-
(如果POSIXLY_CORRECT=1
仅适用于第一个文件)或者任何文件名是-
.如果其中的文件名太多而无法容纳在一个命令行中,它也会失败。
下面的代码与上面的代码存在相同的问题(第四个除外)
for file in `cat large_file_list`
do
gzip -d $file
done
可靠的解决方案
如果您的large_file_list
每行只有一个文件名,并且名为的文件-
不在其中,并且您使用的是 GNU 系统,则使用:
xargs -rd'\n' gzip -d -- <large_file_list
-d'\n'
告诉xargs
将每一行输入视为一个单独的文件名。
-r
告诉xargs
如果输入文件为空则不要运行该命令。
--
告诉gzip
下面的参数不被视为选项,即使它们以 开头-
。-
单独的仍然会被视为而-
不是被调用的文件-
。
xargs
将在每个命令行上放置许多文件名,但数量不会超过命令行限制。这减少了必须启动进程的次数gzip
,因此速度更快。它也是安全的:文件名也将受到保护分词和路径名扩展。
答案2
我怀疑这会很重要。
我会使用循环,只是因为我不知道列表文件中列出了多少个文件,而且我(通常)不知道文件名中是否有空格。当生成的列表长度太长时,执行会生成非常长的参数列表的命令替换可能会导致“参数列表太长”错误。
我的循环看起来像
while IFS= read -r name; do
gunzip "$name"
done <file.list
这还允许我在gunzip
命令之后插入用于处理数据的命令。事实上,根据数据的实际内容以及需要对其执行的操作,甚至可以在不将其保存到文件的情况下对其进行处理:
while IFS= read -r name; do
zcat "$name" | process_data
done <file.list
(哪里process_data
是从标准输入读取未压缩数据的管道)
如果数据处理比解压缩花费的时间更长,则循环是否更有效的问题就变得无关紧要。
理想情况下,我宁愿不处理文件名列表,而是使用文件名通配模式,如
for name in ./*.gz; do
# processing of "$name" here
done
其中./*.gz
有一些与相关文件匹配的模式。这样我们就不会依赖于文件的数量,也不依赖于文件名中使用的字符(它们可能包含换行符或其他空白字符,或者以破折号开头等)
有关的:
答案3
在这两者中,将所有文件传递给一次调用的那个gzip
可能会更快,正是因为您只需要启动gzip
一次。 (也就是说,如果该命令完全有效,请参阅其他答案以了解注意事项。)
但是,我想提醒大家的是优化的黄金法则:不要过早这样做。
在知道这是一个问题之前,不要优化这类事情。
这部分程序需要很长时间吗?好吧,解压缩大文件可能会,而且无论如何你都必须这样做,所以它可能不是那么容易回答。
措施。确实,这是最好的确定方法。
您将亲眼看到结果(或使用您自己的秒表),并且它们将适用于你的情况互联网上的随机答案可能不会。将这两个变体放入脚本中并运行
time script1.sh
, andtime script2.sh
。 (使用空压缩文件列表来测量开销的绝对量。)
答案4
你的磁盘速度有多快?
这应该使用您的所有 CPU:
parallel -X gzip -d :::: large_file_list
因此,您的限制可能是磁盘的速度。
您可以尝试调整-j
:
parallel -j50% -X gzip -d :::: large_file_list
这将像上一个命令一样并行运行一半的作业,并且会减少对磁盘的压力,因此根据您的磁盘,这可能会更快。