作为更多的思想实验,我想看看我们可以推动CLI工具在多大程度上解决这类问题.为此,我想尝试使用快速哈希CLI工具xxHash来完成这项工作.
xxHash is an extremely fast non-cryptographic hash algorithm, working at speeds close to RAM limits. It is proposed in two flavors, 32 and 64 bits.
它可以在每种编程语言中使用,但是对于这个实验,我将使用CLI风格,xxhsum,特别是32位模式,所以xxhsum -H0.
正如您已经发现的那样,正如其他人所说的那样,反复调用哈希函数CLI工具或任何工具通常会使这些类型的方法失败.在这里调用xxhsum 5M次将是使用它的次优方式.它的优势在于文件I / O,那么如果我们采用5M线并将它们转换为5M文件呢?
使用split命令在Linux中执行该任务实际上是微不足道的:
split -l 1 afile
以1M为单位散列这些文件的速度有多快,每个文件都有这样的行.
示例1行文件
$cat datadir/xzeyw
{"name": "John4000", "surname": "Gates", "country": "Germany", "age": "20", "height": "180"}
1M文件的目录
$ls -l datadir | wc -l
1000002
哈希他们的时间
${ time xxhsum -H0 * > ../nfile 2>&1 ;} |& awk '/real|user|sys/ {print $1": "$2"\t"}' | tr -d '\n'
real: 0m6.998s user: 0m5.007s sys: 0m1.569s
是的,这是正确的,花了~7秒!我发现这令人印象深刻.以这种方式使用xxhsum,我们只花了一次运行它的成本,并允许它循环遍历1M文件.
这种方法的缺点
因此,这样做的一个缺点当然是分裂.正如您可以想象的那,这成为我们最昂贵的操作.因为我们必须使用X行获取单个文件并将其作为X文件分解到HDD中,其中包含单行.
以下是一些数据:
./hashy.bash
make data
---------
real: 0m17.492s user: 0m12.434s sys: 0m4.788s
split data
----------
real: 2m15.180s user: 0m0.700s sys: 2m4.443s
hash data
---------
real: 0m6.487s user: 0m5.798s sys: 0m0.459s
在这里我们可以看到我们的分割操作花了大约2分钟.注意:此输出中的第一行显示构建包含1M行JSON的文件的时间.
另一个缺点是我们在命令行上处理的文件数量.我正在使用*,所以这将扩展到1M或5M文件名,这可能被认为是危险的,它是.请记住,当您增加运行的文件数时,可能会超出分配给命令行参数的空间量.
有关命令行长度,请参阅以下链接:
结论
所以你可以想象,使用1M文件或5M文件来解决这样的问题看起来几乎是荒谬的.我必须同意.但它仍然是一个有趣的实验,因为它表明,如果以适当的方式利用CLI工具,您可以从中获得出色的性能.
hashy.bash的代码
如果有人对代码感兴趣:
$cat hashy.bash
#!/bin/bash
echo ""
echo "make data"
echo "---------"
rm -f afile
{ time for i in {0..1000000};do echo "{\"name\": \"John${i}\", \"surname\": \"Gates\", \"country\": \"Germany\", \"age\": \"20\", \"height\": \"180\"}">> afile ;done ;} \
|& awk '/real|user|sys/ {print $1": "$2"\t"}' | tr -d '\n'
echo ""
echo ""
rm -fr datadir && mkdir datadir && cd datadir
echo "split data"
echo "----------"
{ time split -l 1 ../afile ;} |& awk '/real|user|sys/ {print $1": "$2"\t"}' | tr -d '\n'
echo ""
echo ""
echo "hash data"
echo "---------"
{ time xxhsum -H0 * > ../nfile 2>&1 ;} |& awk '/real|user|sys/ {print $1": "$2"\t"}' | tr -d '\n'
cd - > /dev/null 2>&1
echo ""
echo ""
参考