#{}中的命令将以新的子进程中执行而不阻塞父进程
&语法意思是将{}中的代码将作为一个整体切换到后端运行而不阻塞下一次循环,再次执行的效果如下图。
可以看到命令瞬间执行完成。并行化虽然是实现了,但是可以发现shell主进程已经执行完了,才看到子进程的打印,这是因为父进程没有等待子进程完成就退出了。
进一步思考,如果存在任务串行依赖应该怎么做呢?比如有第二步操作需要等待上面的http请求执行完才能执行的需求,应该怎么去改进脚本呢?想到unix下的wait函数,同样shell也有对应的wait命令可用,再次对脚本修改如下。
#!/bin/sh
cat $1 | while read line
curl "http://gztest.gf.com.cn:8000/otcblueup/client_id=010100047752&prod_code=${line}&occur_amount=100000&env_no=146"
#{}中的命令将以新的子进程中执行而不阻塞父进程
echo "wait all task finish,then exit"
echo "success"
执行后wait似乎没有生效,"wait all task finish,then exit"以及"success"在后台进程完成前就输出了,这是因为while循环的输入来自于cat输出到管道中的数据,wait实际等待的是cat命令的结束,用重定向的方式将cat文件的内容传给while循环可解决此问题。
#!/bin/sh
while read line
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!!!"
echo "success"
下面截图展示符合预期的结果,wait等待了所有后台进程完成最后输出success标识。
更进一步,上面的并发是一次性启动了所有任务,这对于机器资源以及性能会有很大影响,有没有什么方式可以控制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<${threadTask};i++))
echo "" >&9
echo "wait all task finish,then exit!!!"
while read line
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 < $1
# 关闭管道
exec 9>&-
echo "success"
并发控制效果如下,并发度设置为2【这样并发控制效果明显】,可以看到一次性启动2个进程任务,每完成一个会重新启动一个新的进程直到所有进程任务完成。
shell脚本简单实用,如果能多多掌握一些shell技巧,将大大提高后端人员日常工作效率。从而减少无效加班,降低代码工作者996.ICU风险。
转自https://www.toutiao.com/a6773190691846619661/?timestamp=1577336958&app=news_article&group_id=6773190691846619661&req_id=201912261309170100140400961B1091A0
喜欢这篇文章?欢迎打赏~~