Shell之多线程
Posted 枫凌傲雪
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Shell之多线程相关的知识,希望对你有一定的参考价值。
单线程案例:
cat 1.sh
date
for i in `seq 1 10`
do
echo sleep 5
sleep 5
done
date
sh 1.sh
输出:
Wed Feb 23 11:22:00 CST 2022
sleep 5
sleep 5
sleep 5
sleep 5
sleep 5
sleep 5
sleep 5
sleep 5
sleep 5
sleep 5
Wed Feb 23 11:22:50 CST 2022
案例说明:脚本按顺序处理10个需求,每个需求处理时长为5秒钟,单线程处理预期耗时为10*5=50s。结果符合预期。
适用场景:前后任务存在依赖。该案例前后任务不存在依赖,可以使用多线程方法减少耗时。
多线程改造案例:
cat 2.sh
date
for i in `seq 1 10`
do
echo sleep 5
sleep 5
&
done
wait
date
sh 2.sh
Wed Feb 23 11:29:30 CST 2022
sleep 5
sleep 5
sleep 5
sleep 5
sleep 5
sleep 5
sleep 5
sleep 5
sleep 5
sleep 5
Wed Feb 23 11:29:35 CST 2022
案例说明:改造案例一的脚本,原理是借用for循环,将任务块...添加&后缀的方式置为后台运行,再使用wait命令等后台任务执行完成后结束脚本状态。
适用于预期任务并发少的场景。
优点:所有任务可以同时处理,耗时短; 缺点:如果任务并发较多,超出系统负载会导致任务失败和服务器性能不稳定等问题。
如何解决并发较多、不可控? 答:预设并发数量,把任务以队列的方式在预设并发内进行处理。
多线程可控并发案例:
cat 3.sh
date
function my_task()
echo "sleep 4"
sleep 4
fifofile="/tmp/$$.fifo"
mkfifo $fifofile
exec 6<>$fifofile
rm -rf $fifofile
thread_num=5
job_num=20
for ((i=0;i<$thread_num;i++)); do
echo >&6
done
for ((i=0;i<$job_num;i++)); do
read -u6
my_task
echo >&6
&
done
wait
exec 6<&-
exec 6>&-
date
sh 3.sh
Wed Feb 23 16:28:30 CST 2022
sleep 4
sleep 4
sleep 4
sleep 4
sleep 4
sleep 4
sleep 4
sleep 4
sleep 4
sleep 4
sleep 4
sleep 4
sleep 4
sleep 4
sleep 4
sleep 4
sleep 4
sleep 4
sleep 4
sleep 4
Wed Feb 23 16:28:46 CST 2022
[admin@vm010010012061 /home/admin]
$ps -ef | grep "sleep 4" | grep -v grep
admin 60736 60732 0 16:28 pts/2 00:00:00 sleep 4
admin 60738 60734 0 16:28 pts/2 00:00:00 sleep 4
admin 60741 60733 0 16:28 pts/2 00:00:00 sleep 4
admin 60747 60740 0 16:28 pts/2 00:00:00 sleep 4
admin 60749 60743 0 16:28 pts/2 00:00:00 sleep 4
[admin@vm010010012061 /home/admin]
$ps -ef | grep "sleep 4" | grep -v grep
admin 61072 60737 0 16:28 pts/2 00:00:00 sleep 4
admin 61073 60750 0 16:28 pts/2 00:00:00 sleep 4
admin 61074 60739 0 16:28 pts/2 00:00:00 sleep 4
admin 61075 60751 0 16:28 pts/2 00:00:00 sleep 4
admin 61076 60754 0 16:28 pts/2 00:00:00 sleep 4
[admin@vm010010012061 /home/admin]
$ps -ef | grep "sleep 4" | grep -v grep
admin 61368 60752 0 16:28 pts/2 00:00:00 sleep 4
admin 61369 60744 0 16:28 pts/2 00:00:00 sleep 4
admin 61370 60746 0 16:28 pts/2 00:00:00 sleep 4
admin 61371 60756 0 16:28 pts/2 00:00:00 sleep 4
admin 61372 60742 0 16:28 pts/2 00:00:00 sleep 4
[admin@vm010010012061 /home/admin]
$ps -ef | grep "sleep 4" | grep -v grep
admin 61995 60753 0 16:28 pts/2 00:00:00 sleep 4
admin 61996 60745 0 16:28 pts/2 00:00:00 sleep 4
admin 61997 60755 0 16:28 pts/2 00:00:00 sleep 4
admin 61998 60735 0 16:28 pts/2 00:00:00 sleep 4
admin 62000 60748 0 16:28 pts/2 00:00:00 sleep 4
案例说明:解决并发不可控问题,预设并发为5个;任务块为my_task函数,测试任务数为20个;每个并发处理4个任务,每个任务执行时长为4秒;预计完成所有任务耗时(20÷5)* 4 = 16秒。符合预期。
脚本逻辑:
第一块代码:定义任务,放入函数中,方便下面调用。
第二块代码:定义并发使用的通道。创建一个管道文件$$.fifo,并将管道文件定义到6号文件描述符(扩展:了解exec和文件描述符,这里的文件描述符可以自行定义,<是读取、>是写入,<>是读写),意思是用6号文件描述符代替管道文件,所有这里将失效的管道文件删除。
第三块代码:预设可用并发数量,预期任务数量。
第四块代码:在6号文件描述符中创建并发位置,注意>和&中间没有空格。
第五块代码:创建任务队列,使用read读取并发位置,执行任务后再执行echo补充上面读取的并发位。
第六块代码:wait等待所有后台任务执行完成再执行下一步,下面两步分别是关闭读取和写入6号文件描述,这里关闭读写需要分两步操作。
以上是关于Shell之多线程的主要内容,如果未能解决你的问题,请参考以下文章
iOS底层探索之多线程(十五)—@synchronized源码分析