xargs具有并行处理的能力,在处理大文件时,如果应用得当,将大幅提升效率。

xargs详细内容(全网最详细):https://www.cnblogs.com/f-ck-need-u/p/5925923.html

效率提升测试结果

先展示一下使用xargs并行处理提升的效率,稍后会解释下面的结果。

测试环境:

  1. win10子系统上
  2. 32G内存
  3. 8核心cpu
  4. 测试对象是一个放在固态硬盘上的10G文本文件(如果你需要此测试文件,点此下载,提取码: 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并行处理工具,它的功能更丰富,效果更强大。

shell高效处理文本(1):xargs并行处理的更多相关文章

  1. shell脚本--显示文本内容

    shell脚本显示文本内容及相关的常用命令有cat.more.less.head.tail.nl 首先是cat,cat最常用的就是一次性显示文件的所有内容,如果一个文件的内容很多的话,那么就不是很方便 ...

  2. shell编程系列24--shell操作数据库实战之利用shell脚本将文本数据导入到mysql中

    shell编程系列24--shell操作数据库实战之利用shell脚本将文本数据导入到mysql中 利用shell脚本将文本数据导入到mysql中 需求1:处理文本中的数据,将文本中的数据插入到mys ...

  3. Shell命令之文本操作

    前言 在Linux中,文本处理操作是最常见的,应用非常广泛,如果能熟练掌握,可以大大提高开发效率. awk/sed/grep是文本操作领域的“三剑客”,学会了这3个命令就可以应对绝大多数文本处理场景. ...

  4. linux —— shell 编程(文本处理)

    导读 本文为博文linux —— shell 编程(整体框架与基础笔记)的第4小点的拓展.(本文所有语句的测试均在 Ubuntu 16.04 LTS 上进行) 目录 基本文本处理 流编辑器sed aw ...

  5. shell 命令合并文本

    之前想把代码打印出来看来着,后来合并完之后放在word里发现有2000多页,然后放弃了~anyway,这个命令还是挺有用的. 比如我有文本a001.dat, a002.dat, a003.dat .. ...

  6. shell命令技巧——文本去重并保持原有顺序

    简单来说,这个技巧相应的是例如以下一种场景 假设有文本例如以下 cccc aaaa bbbb dddd bbbb cccc aaaa 如今须要对它进行去重处理.这个非常easy,sort -u就能够搞 ...

  7. Shell正则表达式和文本处理工具

    作业一:整理正则表达式博客 一.什么是正则 正则就是用一些具有特殊含义的符号组合而成(称为正则表达式)来描述字符或者字符串的方法.或者说:正则就是用来描述一类事物的规则. 通配符是由shell解释得. ...

  8. shell学习笔记2-find和xargs

    1,find命令形式 find pathname -options [-print - exec -ok] pathname find命令所查找的目录路径.. 表示当前目录,/表示系统根路径 -pri ...

  9. shell学习(20)- xargs

    xargs 是给命令传递参数的一个过滤器,也是组合多个命令的一个工具. xargs 可以将管道或标准输入(stdin)数据转换成命令行参数,也能够从文件的输出中读取数据. xargs 也可以将单行或多 ...

随机推荐

  1. hbase删除table时,显示table不存在

    hbase删除table时,显示table不存在,但是创建table时,显示table存在. 解决方案: 清空zookeeper数据.(重新安装zookeeper)

  2. Mybatis的JDBC提交设置/关闭mysql自动提交------关于mysql自动提交引发的惨剧

    学习Mybatis时提到了JDBC方式需要自己手动提交事务,如果不加session.commit会导致数据库的数据无法正常插入(程序本身又不给你报错,还装出一副我已经插入成功的样子) SqlSessi ...

  3. Python开发系列

    一  Python基础理论 Python简介 数据类型 字符编码与文件操作 函数 模块与包 常用模块 面向对象 网络编程 相关代码示例参考 https://github.com/Jonathan131 ...

  4. 【转载】ARCHIVE_LAG_TARGET参数的作用(定时切换redo)

    (一)  设置archive_lag_target参数1.      一旦设置了archive_lag_target初始化参数,数据库将会周期性的检查实例的当前重做日志.如果遇到下列情况,实例将会切换 ...

  5. C++ 基础知识回顾总结

    一.前言 为啥要写这篇博客?答:之前学习的C和C++相关的知识,早就被自己忘到一边去了.但是,随着音视频的学习的不断深入,和C/C++打交道的次数越来越多,看代码是没问题的,但是真到自己操刀去写一些代 ...

  6. wordpress背景添加跟随鼠标动态线条特效

    今天看到别人的博客,在鼠标移动背景时会出现线条动态特效 感觉挺有意思的,还有另一种,在背景点击时会跳出字符特意去找了方法,以为需要添加代码的,结果只要安装个插件就可以了,所以说wordpress就是方 ...

  7. 项目文件与 SVN 资源库同步提示错误 Attempted to lock an already-locked dir

    问题描述 之前为了图方便,在eclipse中直接把三个jsp文件复制到了eclipse中我新建的一个文件夹中,把svn版本号信息也带过来了,然后我又删除了这三个jsp文件,接着先把这三个jsp复制到桌 ...

  8. java后端服务器读取excel将数据导入数据库

    使用的是easypoi,官网文档:http://easypoi.mydoc.io/ /** * 导入Excel文件 */ @PostMapping("/importTeacher" ...

  9. java常见面试题及部分答案

    1.Redis常见的存储数据类型 list(列表类型) set(集合类型) zset(有序集合类型) string(字符串类型) hash(散装类型) 2.log4j的级别 debug:日志的最低级别 ...

  10. linux查看系统32位还是64位

    1. 从系统查看 1.1 uname -a 命令 [root@qs-dmm-rh2 ~]# uname -a Linux qs-dmm-rh2 2.6.18-194.el5 #1 SMP Tue Ma ...