xargs 具有并行处理的能力, 在处理大文件时, 如果应用得当, 将大幅提升效率.
xargs 详细内容(全网最详细):https://www.cnblogs.com/f-ck-need-u/p/5925923.html
效率提升测试结果
先展示一下使用 xargs 并行处理提升的效率, 稍后会解释下面的结果.
测试环境:
win10 子系统上
32G 内存
8 核心 CPU
测试对象是一个放在固态硬盘上行的 10G 文本文件(如果你需要此测试文件, 点此下载 https://pan.baidu.com/s/1l17GJl0tTBFjDfZ_fRxDqA , 提取码: semu)
下面是正常情况下 wc -l 统计这个 10G 文件行数的结果, 花费 16 秒, 多次测试, CPU 利用率基本低于 80%.
- $ /usr/bin/time wc -l 9.txt
- 999999953 9.txt
- 4.56user 3.14system 0:16.06elapsed 47%CPU (0avgtext+0avgdata 740maxresident)k
- 0inputs+0outputs (0major+216minor)pagefaults 0swaps
通过分割文件, 使用 xargs 的并行处理功能进行统计, 花费时间 1.6 秒, CPU 利用率 752%:
- $ /usr/bin/time ./b.sh
- 999999953
- 7.67user 4.54system 0:01.62elapsed 752%CPU (0avgtext+0avgdata 1680maxresident)k
- 0inputs+0outputs (0major+23200minor)pagefaults 0swaps
用 grep 从这个 10G 的文本文件中筛选数据, 花费时间 24 秒, CPU 利用率 36%:
- $ /usr/bin/time grep "10000" 9.txt>/dev/null
- 6.17user 2.57system 0:24.19elapsed 36%CPU (0avgtext+0avgdata 1080maxresident)k
- 0inputs+0outputs (0major+308minor)pagefaults 0swaps
通过分割文件, 使用 xargs 的并行处理功能进行统计, 花费时间 1.38 秒, CPU 利用率 746%:
- $ /usr/bin/time ./a.sh
- 6.01user 4.34system 0:01.38elapsed 746%CPU (0avgtext+0avgdata 1360maxresident)k
- 0inputs+0outputs (0major+31941minor)pagefaults 0swaps
速度提高的不是一点点.
xargs 并行处理简单示例
要使用 xargs 的并行功能, 只需使用 "-P N" 选项即可, 其中 N 是指定要运行多少个并行进程, 如果指定为 0, 则使用尽可能多的并行进程数量.
需要注意的是:
既然要并行, 那么 xargs 必须得分批传送管道的数据, xargs 的分批选项有 "-n","-i","-L", 如果不知道这些内容, 看本文开头给出的文章.
并行进程数量应该设置为 CPU 的核心数量. 如果设置为 0, 在处理时间较长的情况下, 很可能会并发几百个甚至上千个进程. 在我测试一个花费 2 分钟的操作时, 创建了 500 多个进程.
在本文后面, 还给出了其它几个注意事项.
例如, 一个简单的 sleep 命令, 在不使用 "-P" 的时候, 默认是一个进程按批的先后进行处理:
- [root@xuexi ~]# time echo {
- 1..4
- } | xargs -n 1 sleep
- real 0m10.011s
- user 0m0.000s
- sys 0m0.011s
总共用了 10 秒, 因为每批传一个参数, 第一批睡眠 1 秒, 然后第二批睡眠 2 秒, 依次类推, 还有 3 秒, 4 秒, 共 1+2+3+4=10 秒.
如果使用 - P 指定 4 个处理进程, 它将以处理时间最长的为准:
- [root@xuexi ~]# time echo {
- 1..4
- } | xargs -n 1 -P 4 sleep
- real 0m4.005s
- user 0m0.000s
- sys 0m0.007s
再例如, find 找到一大堆文件, 然后用 grep 去筛选:
- find /path -name "*.log" | xargs -i grep "pattern" {
- }
- find /path -name "*.log" | xargs -P 4 -i grep "pattern" {
- }
上面第一个语句, 只有一个 grep 进程, 一次处理一个文件, 每次只被其中一个 CPU 进行调度. 也就是说, 它无论如何, 都只用到了一核 CPU 的运算能力, 在极端情况下, CPU 的利用率是 100%.
上面第二个语句, 开启了 4 个并行进程, 一次可以处理从管道传来的 4 个文件, 在同一时刻这 4 个进程最多可以被 4 核不同的 CPU 进行调度, 在极端情况下, CPU 的利用率是 400%.
并行处理示例
下面是文章开头给出的实验结果对应的示例. 一个 10G 的文本文件 9.txt, 这个文件里共有 9.9 亿 (具体的是 999999953) 行数据.
首先一个问题是, 怎么统计这么近 10 亿行数据的? wc -l, 看看时间花费.
- $ /usr/bin/time wc -l 9.txt
- 999999953 9.txt
- 4.56user 3.14system 0:16.06elapsed 47%CPU (0avgtext+0avgdata 740maxresident)k
- 0inputs+0outputs (0major+216minor)pagefaults 0swaps
总共花费了 16.06 秒, CPU 利用率是 47%.
随后, 我把这 10G 数据用 split 切割成了 100 个小文件, 在提升效率方面, split 切割也算是妙用无穷:
split -n l/100 -d -a 3 9.txt fs_
这 100 个文件, 每个 105M, 文件名都以 "fs_" 为前缀:
- $ ls -lh fs* | head -n 5
- -rwxrwxrwx 1 root root 105M Oct 6 17:31 fs_000
- -rwxrwxrwx 1 root root 105M Oct 6 17:31 fs_001
- -rwxrwxrwx 1 root root 105M Oct 6 17:31 fs_002
- -rwxrwxrwx 1 root root 105M Oct 6 17:31 fs_003
- -rwxrwxrwx 1 root root 105M Oct 6 17:31 fs_004
然后, 用 xargs 的并行处理来统计, 以下是统计脚本 b.sh 的内容:
- #!/usr/bin/env bash
- find /mnt/d/test -name "fs*" |\
- xargs -P 0 -i wc -l {} |\
- awk '{sum += $1}END{print sum}'
上面用 - P 0 选项指定了尽可能多地开启并发进程数量, 如果要保证最高效率, 应当设置并发进程数量等于 CPU 的核心数量(在我的机器上, 应该设置为 8), 因为在操作时间较久的情况下, 可能会并行好几百个进程, 这些进程之间进行切换也会消耗不少资源.
然后, 用这个脚本去统计测试:
- $ /usr/bin/time ./b.sh
- 999999953
- 7.67user 4.54system 0:01.62elapsed 752%CPU (0avgtext+0avgdata 1680maxresident)k
- 0inputs+0outputs (0major+23200minor)pagefaults 0swaps
只花了 1.62 秒, CPU 利用率 752%. 和前面单进程处理相比, 时间是原来的 16 分之 1,CPU 利用率是原来的好多好多倍.
再来用 grep 从这个 10G 的文本文件中筛选数据, 例如筛选包含 "10000" 字符串的行:
- $ /usr/bin/time grep "10000" 9.txt>/dev/null
- 6.17user 2.57system 0:24.19elapsed 36%CPU (0avgtext+0avgdata 1080maxresident)k
- 0inputs+0outputs (0major+308minor)pagefaults 0swaps
24 秒, CPU 利用率 36%.
再次用 xargs 来处理, 以下是脚本:
- #!/usr/bin/env bash
- find /mnt/d/test -name "fs*" |\
- xargs -P 8 -i grep "10000" {}>/dev/null
测试结果:
- $ /usr/bin/time ./a.sh
- 6.01user 4.34system 0:01.38elapsed 746%CPU (0avgtext+0avgdata 1360maxresident)k
- 0inputs+0outputs (0major+31941minor)pagefaults 0swaps
花费时间 1.38 秒, CPU 利用率 746%.
这比用什么 ag,ack 替代 grep 有效多了.
提升哪些效率以及注意事项
xargs 并行处理用的好, 能大幅提升效率, 但这是有条件的.
首先要知道, xargs 是如何提升效率的, 以 grep 命令为例:
ls fs* | xargs -i -P 8 grep 'pattern' {}
之所以 xargs 能提高效率, 是因为 xargs 可以分批传递管道左边的结果给不同的并发进程, 也就是说, xargs 要高效, 得有多个文件可处理. 对于上面的命令来说, ls 可能输出了 100 个文件名, 然后 1 次传递 8 个文件给 8 个不同的 grep 进程.
还有一些注意事项:
1. 如果只有单核心 CPU, 像提高效率, 没门
2.xargs 的高效来自于处理多个文件, 如果你只有一个大文件, 那么需要将它切割成多个小片段
3. 由于是多进程并行处理不同的文件, 所以命令的多行输出结果中, 顺序可能会比较随机
例如, 统计行数时, 每个文件的出现顺序是不受控制的.
- 10000000 /mnt/d/test/fs_002
- 9999999 /mnt/d/test/fs_001
- 10000000 /mnt/d/test/fs_000
- 10000000 /mnt/d/test/fs_004
- 9999999 /mnt/d/test/fs_005
- 9999999 /mnt/d/test/fs_003
- 10000000 /mnt/d/test/fs_006
- 9999999 /mnt/d/test/fs_007
不过大多数时候这都不是问题, 将结果排序一下就行了.
4.xargs 提升效率的本质是 CPU 的利用率, 因此会有内存, 磁盘速度的瓶颈. 如果内存小, 或者磁盘速度慢(将因为加载数据到内存而长时间处于 io 等待的睡眠状态),xargs 的并行处理基本无效.
例如, 将上面 10G 的文本文件放在虚拟机上, 机械硬盘, 内存 2G, 将会发现使用 xargs 并行和普通的命令处理几乎没有差别, 因为绝大多数时间都花在了加载文件到内存的 io 等待上.
下一篇文章将介绍 GNU parallel 并行处理工具, 它的功能更丰富, 效果更强大.
来源: https://www.cnblogs.com/f-ck-need-u/p/9752365.html