shell 脚本 no coprocess_什么?Shell也能并行化

作为一名后台开发,写shell脚本可能是工作中避免不了的,比如日志分析过滤、批量请求和批量插入数据等操作,这些如果单纯靠人工手动去处理既费时又费力,有了shell脚本就可以轻松搞定,当然有人会说可以用python或者其他编程语言,这并不是不可以,但没有哪个有shell这么简单方便快捷的。需要依赖库不说,还要懂对应语言的语法才行。

不知道大家在工作中有没有经常会遇到测试或者产品跑过来说要在数据库批量插入大量的样本数据,在下就经常遇到,比如昨天测试同学就找上门需要对一批用户调用http接口进行一系列操作,很自然想到对用户文件进行while循环读取然后调用curl命令发送http请求,于是写出如下脚本代码:

#! /bin/sh#$1 为用户列表文件,以参数形式传入cat $1 | while read linedo    curl "http://gztest.gf.com.cn:8000/otcblueup/?client_id=010100047752&prod_code=${line}&occur_amount=100000&env_no=146"done

这样写有没有问题?功能性的问题自然是没有,但是存在性能问题,实际的运行效果是这样的。

fd7a0015990e6c94c3d6cbd917723488.gif

效果图一

命令是串行执行的,批量处理的场景往往数据量比较大,再加上中间的网络延时,往往需要等待很长时间才能彻底执行完成【如果愿意等也无所谓】。作为程序员对技术的追求是极致的,学过那么多语言的并发技能(进程、线程、协程、异步多路复用等),shell脚本是否也可以进行并发呢?对上面的串行代码进行修改如下:

#! /bin/sh#$1 为用户列表文件,以参数形式传入cat $1 | while read linedo    {        echo $line        curl "http://gztest.gf.com.cn:8000/otcblueup/?client_id=010100047752&prod_code=${line}&occur_amount=100000&env_no=146"    }& #{}中的命令将以新的子进程中执行而不阻塞父进程done

&语法意思是将{}中的代码将作为一个整体切换到后端运行而不阻塞下一次循环,再次执行的效果如下图。

a24d882a6b90d78337c8b6ce738792bb.gif

效果图二

可以看到命令瞬间执行完成。并行化虽然是实现了,但是可以发现shell主进程已经执行完了,才看到子进程的打印,这是因为父进程没有等待子进程完成就退出了。

进一步思考,如果存在任务串行依赖应该怎么做呢?比如有第二步操作需要等待上面的http请求执行完才能执行的需求,应该怎么去改进脚本呢?想到unix下的wait函数,同样shell也有对应的wait命令可用,再次对脚本修改如下。

#!/bin/shcat $1 | while read linedo    {        curl "http://gztest.gf.com.cn:8000/otcblueup/?client_id=010100047752&prod_code=${line}&occur_amount=100000&env_no=146"    }& #{}中的命令将以新的子进程中执行而不阻塞父进程doneecho "wait all task finish,then exit"waitecho "success"
b6e0257f55d0d150c7392a031ecf5c61.gif

效果图三

执行后wait似乎没有生效,"wait all task finish,then exit"以及"success"在后台进程完成前就输出了,这是因为while循环的输入来自于cat输出到管道中的数据,wait实际等待的是cat命令的结束,用重定向的方式将cat文件的内容传给while循环可解决此问题。

#!/bin/shwhile read linedo    {        curl "http://gztest.gf.com.cn:8000/otcblueup/?client_id=010100047752&prod_code=${line}&occur_amount=100000&env_no=146"    }& #{}中的命令将以新的子进程中执行而不阻塞父进程done < $1 #重定向echo "wait all task finish,then exit!!!"waitecho "success"

下面截图展示符合预期的结果,wait等待了所有后台进程完成最后输出success标识。

16ffd8c6565131abb1becc285e692d5f.png

效果图四

更进一步,上面的并发是一次性启动了所有任务,这对于机器资源以及性能会有很大影响,有没有什么方式可以控制shell进程并发度呢?这里介绍一种利用管道进行并发控制方式。用mkfifo创建first in first out管道,控制并发逻辑如下。

#!/bin/bash#并发数threadTask=2#创建fifo管道fifoFile="test_fifo"rm -f ${fifoFile}mkfifo ${fifoFile}# 建立文件描述符关联exec 9<> ${fifoFile}rm -f ${fifoFile}# 预先向管道写入数据for ((i=0;i&9doneecho "wait all task finish,then exit!!!"while read linedo    read -u9    {        curl "http://gztest.gf.com.cn:8000/otcblueup/?client_id=010100047752&prod_code=${line}&occur_amount=100000&env_no=146"        echo "" >&9    }& #{}中的命令将以新的子进程中执行而不阻塞父进程done < $1wait# 关闭管道exec 9>&-echoecho "success"

并发控制效果如下,并发度设置为2【这样并发控制效果明显】,可以看到一次性启动2个进程任务,每完成一个会重新启动一个新的进程直到所有进程任务完成。

d99f73f917f43e779c347b1fda3c38a8.gif

效果图五

总结:

shell脚本简单实用,如果能多多掌握一些shell技巧,将大大提高后端人员日常工作效率。从而减少无效加班,降低代码工作者996.ICU风险。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值