php shell并行执行_shell并行执行 - CSDN
精华内容
参与话题
  • Shell-使用&和wait让你的脚本并行执行

    万次阅读 多人点赞 2019-12-30 21:27:46
    假定业务上多个业务逻辑没有先后关系,每个脚本的执行时间也很长 ,推荐并行执行。 一般情况下,我们会把每个业务逻辑写到一个单独的脚本里,在服务器上逐一调用,每次都要手工去敲命令。 如果我们把这些脚本放到一个...


    在这里插入图片描述


    概述

    我们知道shell中的命令都是串行执行的,如果想要充分利用服务器的资源,就需要些小技巧了。

    假定业务上多个业务逻辑没有先后关系,每个脚本的执行时间也很长 ,推荐并行执行。

    一般情况下,我们会把每个业务逻辑写到一个单独的脚本里,在服务器上逐一调用,每次都要手工去敲命令。

    如果我们把这些脚本放到一个调用脚本里呢? 执行的时候去调用这个调用脚本,事实上linux会根据脚本中的顺序 串行去调用这些脚本,还不如自己在服务器上一个个的执行快呢,最起码手工逐个调用脚本还是并行的。


    常见的串行执行

    我们通过一个例子来演示下:

    在这里插入图片描述

    使用1.sh和2.sh模拟业务逻辑

    [root@artisan test]# cat 1.sh 
    #!/bin/bash
    echo "1.sh 开始执行....."
    echo "模拟业务逻辑,sleep 5秒, duang duang  duang~~~"
    sleep 5s
    echo "1.sh 执行结束....."
    
    [root@artisan test]# cat 2.sh
    #!/bin/bash
    echo "2.sh 开始执行....."
    echo "模拟业务逻辑,sleep 5秒, duang duang  duang~~~"
    sleep 5s
    echo "2.sh 执行结束....."
    [root@artisan test]# 
    
    

    我们将调用脚本放到 call_serial.sh

    [root@artisan test]# cat call_serial.sh 
    #!/bin/bash
    #当前目录下执行如下脚本  相对路径
    ./1.sh 
    ./2.sh 
    echo "继续执行剩下的逻辑..."
    [root@artisan test]# 
    
    

    执行call_serial.sh
    在这里插入图片描述

    call_serial.sh 可知为【串行


    使用&和wait改造

    • 在每个进程中使用&符号进行让脚本在后台运行,无需等待当前进程结束。
    • 为了确保每个进程都执行完成,最后务必使用wait关键字,用来确保每一个子进程都执行完成。
    [root@artisan test]# cat call_parallel.sh 
    #!/bin/bash
    #当前目录下执行如下脚本  相对路径
    ./1.sh &
    ./2.sh &
    wait
    echo "继续执行剩下的逻辑..."
    [root@artisan test]# 
    
    

    执行下看看效果
    在这里插入图片描述

    call_parallel.sh 可知为【并行

    通过上述的改造,可以大大的提高多个进程并发执行的效率。 对于可以同时执行的业务逻辑,可以充分利用主机资源,减少等待时间。


    示例二

    在这里插入图片描述

    serial.sh

    #!/bin/bash
    beginTime=`date +%s`
    num=1
    for i in `seq 1 3`
    do
        echo $i  "业务逻辑 开始执行,当前时间:" `date "+%Y-%m-%d %H:%M:%S"`
    	sleep 2s
    	echo $i  "业务逻辑 执行完成,当前时间:" `date "+%Y-%m-%d %H:%M:%S"`
    	echo "-----------------------------------------------------------"
    done
    endTime=`date +%s`
    echo "总共耗时:" $(($endTime-$beginTime)) "秒"
    
    

    在这里插入图片描述

    从执行结果来看,串行,每个进程都要耗时2秒,3个进程6秒处理完成


    使用&和wait关键字来改造上上述脚本,使其并行执行

    parallel.sh

    #!/bin/bash
    beginTime=`date +%s`
    num=1
    for i in `seq 1 3`
    do
    	{	
           	echo $i  "业务逻辑 开始执行,当前时间:" `date "+%Y-%m-%d %H:%M:%S"`
    		sleep 2s
    		echo $i  "业务逻辑 执行完成,当前时间:" `date "+%Y-%m-%d %H:%M:%S"`
    		echo "-----------------------------------------------------------"
    	# 结尾的&确保每个进程后台执行
    	}&
    done
    # wait关键字确保每一个子进程都执行完成
    wait
    endTime=`date +%s`
    echo "总共耗时:" $(($endTime-$beginTime)) "秒"
    
    

    在这里插入图片描述
    从执行结果来看,并行,同时启动3个进程,3个进程2秒处理完成。


    展开全文
  • Shell 实现多任务并发

    万次阅读 2016-05-17 09:02:00
    实现一个shell进程库,通过类似于init,run,wait几个简单的命令,就可以迅速实现多进程并发,伪码如下: process_init # 创建进程for city in ${cities[*]}do cmd="handler $city" process_run $cmd ...

    实现思路

    实现一个shell进程库,通过类似于initrunwait几个简单的命令,就可以迅速实现多进程并发,伪码如下:

    process_init # 创建进程
    for city in ${cities[*]}
    do
    cmd="handler $city"
    process_run $cmd
    done
    process_wait # 等待进程

    原理解析

    在实现C++线程库的时候,通常会有一个任务队列,线程从队列中取任务并运行。在实现shell进程库的时候,采用了类似原理,通过一个有名管道充当任务队列。严格来说,并不是一个任务队列,而是一个令牌桶。进程从桶中取得令牌后才可以运行,运行结束后将令牌放回桶中。没有取得令牌的进程不能运行。令牌的数目即允许并发的最大进程数。


    管道

    主要思路:通过mkfifo创建一个有名管道,将管道与一个文件描述符绑定,通过往管道中写数据的方式,控制进程数量。

    function _create_pipe()
    {
    _PROCESS_PIPE_NAME=$(_get_uid)

    mkfifo ${_PROCESS_PIPE_NAME}
    eval exec "${_PROCESS_PIPE_ID}""<>${_PROCESS_PIPE_NAME}"

    for ((i=0; i < $_PROCESS_NUM; i++))
    do
    echo -ne "\n" 1>&${_PROCESS_PIPE_ID}
    done
    }

    exec

    exec fd <  file  #以读方式打开文件,并关联文件描述符fd
    exec fd > file #以写方式打开文件,并关联文件描述符fd
    exec fd <> file #以读写方式打开文件,并关联文件描述符
    # 测试
    exec 8>file
    echo "hello word!" 1>&8

    eval

    为了让程序有一定的扩展性,不想写死fd,因而引入了变量。

    file_fd=8
    exec ${file_fd}>file
    # 测试
    bash test.sh
    test.sh: line 7: exec: 8: not found

    原因:shell在重定向操作符(<、>)左边不进行变量展开。因而引入eval命令,强制shell进行变量展开。 
    eval exec "${fd}>file"简单的说,eval将右边参数整体作为一个命令,进行变量的替换,然后将替换后的输出结果给shell去执行。

    进程关系

    命令执行

    function process_run()
    {
    cmd=$1
    if [ -z "$cmd" ]; then
    echo "please input command to run"
    _delete_pipe
    exit 1
    fi

    _process_get
    {
    $cmd
    _process_post
    }&
    }

    _process_get从管道中取得一个令牌,创建一个进程执行任务,任务执行完毕后,通过_process_post令牌放回管道。

    进程创建

    chengsun@153_92:~/test> bash process_util.sh
    chengsun@153_92:~/test> pstree -a

    |`-sshd
    | |-bash
    | | `-bash process_util.sh #爷爷
    | | |-bash process_util.sh #爸爸
    | | | `-a.out #儿子
    | | |-bash process_util.sh
    | | | `-a.out
    | | `-bash process_util.sh
    | | `-a.out

    脚本运行后,通过pstree命令,得到如上父子进程关系。稍微做一下解释:当运行脚本bash process_util.sh的时候,创建一个shell进程,相当于爷爷被创建起来,而遇到{ command1; command2 } &时,shell 又创建一个子shell进程(爸爸进程)处理命令序列;而对于每一个外部命令,shell都会创建一个子进程运行该命令,即儿子进程被创建。

    困惑:为什么处理{ command1; command2; } &需要单独创建子进程? 
    按照bash manual说法,{ list }并不会创建一个新的shell来运行命令序列。但由于加入&,代表将命令族放入后台执行,就必须新开subshell,否则shell会阻塞。

    进程组

    chengsun@153_92:~/test> ps -f -e -o pid,ppid,pgid,comm

    PID PPID PGID COMMAND
    24904 21976 24904 bash
    19885 24904 19885 \_ bash # 爷爷
    19893 19885 19885 \_ bash # 爸爸
    19894 19893 19885 | \_ a.out # 儿子
    19895 19885 19885 \_ bash
    19896 19895 19885 | \_ a.out
    19897 19885 19885 \_ bash
    19898 19897 19885 \_ a.out

    Shell 将运行process_util的一堆进程置于一个进程组中。其中爷爷进程作为该进程组的组长,pid == pgid。

    wait

    wait pid:阻塞等待某个进程结束; 如果没有指定参数,wait会等待所有子进程结束。

    清理函数

    允许任务通过CTRL+C方式提前结束,因而需要清理函数

    信号

    trap 
    类似C语言signal函数,为shell脚本注册信号处理函数。trap arg signals,其中signals为注册的信号列表,arg为收到信号后执行某个命令。

    function Print
    {
    echo "Hello World!"
    }

    trap Print SIGKILL

    kill 
    kill 命令给进程或进程组发送信号;kill pid 给进程发送默认信号SIGTERM, 通知程序终止执行。

    void sig_handler(int signo)
    {
    printf("sigterm signal\n");
    }

    int main()
    {
    signal(SIGTERM, sig_handler);
    sleep(100);

    return 0;
    }
    chengsun@153_92:~/test> ./a.out &
    [1] 19254
    chengsun@153_92:~/test> kill 19254
    sigterm signal

    kill 0:给当前进程组发送默认信号SIGTERM

    chengsun@153_92:~/test> man kill
    0 All processes in the current process group are signaled.

    清理

    function _clean_up
    {
    # 清理管道文件
    _delete_pipe

    kill 0
    kill -9 $$
    }

    trap _clean_up SIGINT SIGHUP SIGTERM SIGKILL

    kill -9 $$ 非常重要


    实际上,最上层是爷爷进程,当发送Ctrl + C命令的时候,爷爷进程捕获SIGINT信号,调用_clean_up函数。爷爷进程对整个进程组发送SIGTERM信号,并调用kill -9结束自己。爸爸进程接收SIGTERM信号,同时也发送SIGTERN给整个进程组,如果没有kill -9,爸爸进程始终无法结束,进入无限递归环节。儿子为CPP二进制程序,内部没有捕获SIGTERM,该信号默认动作是结束进程。

    使用范例

    # file: run.sh
    #!/bin/sh

    #load process library
    source ./process_util.sh

    function handler()
    {
    city=$1
    ./main ${city}
    }

    process_init 23
    for city in $cities
    do
    cmd = "handler $city"
    process_run "$cmd"
    done
    process_wait
    展开全文
  • 今天在搞一个需求,需要在shell里同时运行两个互不干扰的指令, 主要是在脚本里要让一个apk同时在不同的设备上运行,但是如果在脚本里将命令一行一行堆砌起来的话,这样的代码是串行的,我的mentor让我将脚本改成...

    今天在搞一个需求,需要在shell里同时运行两个互不干扰的指令,

    主要是在脚本里要让一个apk同时在不同的设备上运行,但是如果在脚本里将命令一行一行堆砌起来的话,这样的代码是串行的,我的mentor让我将脚本改成并行的,并且在jenkins跑,jenkins里支持M/S模式,即一台主机,外加多个节点这样的配置。但不是支持多台手机并行的。

    所以只能在脚本上做做工作,

    解决方案很简单:至于要在想要并行的命令之间加个'$'符号

    如下:
    以前的命令片段:

    adb -s bff1bca4 shell am instrument -e class com.dianping.nova.testall.TestAll -w com.alipay.android.app.test/com.dianping.instrumentationTestRunner.InstrumentationTestRunner
    adb -s 040ABG8KF8WE shell am instrument -e class com.dianping.nova.testall.TestAll -w com.alipay.android.app.test/com.dianping.instrumentationTestRunner.InstrumentationTestRunner

    此时在jenkins里是串行的

    改造之后的命令 :

    adb -s bff1bca4 shell am instrument -e class com.dianping.nova.testall.TestAll -w com.alipay.android.app.test/com.dianping.instrumentationTestRunner.InstrumentationTestRunner&adb -s 040ABG8KF8WE shell am instrument -e class com.dianping.nova.testall.TestAll -w com.alipay.android.app.test/com.dianping.instrumentationTestRunner.InstrumentationTestRunner

    注意两个命令要放在同一行

    这样在shell下活jenkins下就是并行执行的了

    展开全文
  • Shell脚本中的多任务并发执行

    千次阅读 2019-06-20 11:53:06
    正常情况下,Shell脚本中的命令是串行执行的,当一条命令执行完才会执行接下来的命令。比如下面这段代码: #!/bin/bash for i in {1..10};do echo $i done echo "END" 执行结果: 1 2 3 4 5 6 7 8 9 10 END 可以...

    正常情况下,Shell脚本中的命令是串行执行的,当一条命令执行完才会执行接下来的命令。比如下面这段代码:

     #!/bin/bash
    for i in {1..10};do
    echo $i 
    done
    echo "END"

    执行结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    END

    可以看到,循环体中的“echo $i”命令是串行执行的。但是如果所执行的命令耗时比较长,这就会导致整个程序的执行时间非常长,甚至可能导致程序执行时卡在那里,长时间失去响应。
    比如我们需要完成这样一个任务:编写一个脚本,扫描192.168.80.0/24网络里,当前在线的主机有哪些,能ping通就认为在线。
    要完成这个任务,编写脚本并不复杂,下面是写好的代码:

     #!/bin/bash
    for i in {1..254};do
            ip="192.168.80.$i"
            ping -c 2 $ip &> /dev/null && echo $ip is up 
    done

    这里对脚本中使用的ping命令稍作说明。Linux中的ping命令在执行后会连续不断地发包,因而脚本中的ping命令使用了“-c”选项,指定只发2次包,如果能收到响应,就认为目标主机在线。
    这个脚本在逻辑上并没有问题,但是在执行后由于要对网络中的254个IP地址轮流执行ping命令,耗时非常长,而且此时的脚本无法使用Ctrl+C强制终止,只能使用Ctrl+Z转入后台,然后再用kill命令强制结束进程。

     [root@localhost ~]# bash ping.sh
    192.168.80.1 is up
    192.168.80.2 is up
    ^C
    ^Z
    [1]+  已停止               bash ping.sh
    [root@localhost ~]# jobs -l                             #查看后台工作任务
    [1]+ 101100 停止                  bash ping.sh
    [root@localhost ~]# kill -9 101100                      #强制结束进程
    [root@localhost ~]# 
    [1]+  已杀死               bash ping.sh

    实际上在这个脚本中所循环执行的ping命令之间并没有依赖关系,也就是说不必非要等到“ping 192.168.80.1”结束之后才能接着执行“ping 192.168.80.2”,所有的这些ping命令完全可以并发执行。
    如果是使用Python,那么可以借助于多线程技术来实现命令的并发执行,而Shell不支持多线程,因而只能采用多进程的方式。具体的实现方法很简单,就是在要并发执行的命令后面加上“&”,将其转入后台执行,这样就可以在执行完一条命令之后,不必等待其执行结束,就立即转去执行下一条命令。
    我们还是以之前的代码为例,在循环体中的echo命令之后加上“&”:

     #!/bin/bash
    for i in {1..10};do
    echo $i &
    done
    echo "END"

    执行结果:

     [root@localhost ~]# bash test.sh
    END
    [root@localhost ~]# 1
    2
    3
    6
    7
    4
    8
    9
    10
    5

    可以看到,在并发执行时不能保证命令的执行顺序,而且本应在整个循环执行结束之后再执行的echo "END"命令,却在程序一开始就被执行了。所以在并发执行时,我们通常都需要保证在循环体中的所有命令都执行完后再向后执行接下来的命令,这时就可以使用 wait命令来实现。在Shell中使用wait命令,相当于其它高级语言里的多线程同步。
    下面对代码进行改进,增加wait命令:

     #!/bin/bash
    for i in {1..10};do
    echo $i &
    done
    wait
    echo "END"

    这样执行结果就正常了:

     [root@localhost ~]# bash test3.sh
    6
    7
    2
    3
    4
    8
    9
    10
    5
    1
    END

    了解了程序并发执行的原理之后,我们对ping脚本也同样进行改进:

     #!/bin/bash
    for i in {1..254};do
            ip="192.168.80.$i"
            ping -c 2 $ip &> /dev/null && echo $ip is up &
    done
    wait

    此时脚本的执行速度将大大提高:

     [root@localhost ~]# bash ping.sh
    192.168.80.10 is up
    192.168.80.20 is up
    192.168.80.2 is up
    192.168.80.1 is up
    192.168.80.135 is up

    因而当要循环执行的命令之间没有依赖关系时,完全可以采用并发执行的方式,这样可以大幅提高代码执行效率。当然并发执行也有缺陷,就是当需要并行执行的命令数量特别多,特别是所执行的命令占用的系统资源非常多时,可能会将整个系统的资源全部耗尽,影响其它程序的运行,因而还可以借助其它技术来限制并发执行的进程数量,由于比较复杂,本文就不做介绍了。

    转载于:https://blog.51cto.com/yttitan/2409618

    展开全文
  • shell多个脚本同时执行

    千次阅读 2019-05-05 01:31:28
    1、编写多进程实验脚本 demo.sh #!/bin/bash >sub1.log;>sub2.log;>sub3.log function sub1 { for i in {1..5} do echo `date +%T` >> sub1.log #注意date 和+号之间有...如:date +%m/%ddate取"月...
  • linux shell 执行多个命令的方法

    万次阅读 2011-10-24 10:09:01
    &&表示:若前一个命令执行成功,才会执行下一个。这样,可确保所有的命令执行完毕后,其执行过程都是成功的 这种执行方法,经常运用在自动安装的Script中。 例如:自动安装Apache及PHP的Script文件: #! /bin/...
  • shell实现队列控制并发执行脚本

    千次阅读 2018-07-31 17:46:05
    默认的shell脚本是串行的,当有大量文件的时候,要进行循环一个个的过滤出来,这个过程需要比较久,效率也比较低。通过查找资料,对脚本进行调整,实现并发执行,具体如下: #!/bin/bash date DIR=/test/log/ ...
  • for example <code>shell_exec("cd ..; dir") but I am unable to find how to execute a few commands, what is the seperator? is it ;, is it /n? nothing seems to work. <p>Please note I am running with ...
  • 提高shell脚本执行效率

    千次阅读 2018-01-19 09:48:36
    Shell脚本程序的执行是顺序执行,而非并行执行的。这很大程度上浪费了可能能利用上的系统资源。 Shell每执行一个命令就创建一个新的进程,如果脚本编写者没有这方面意识,编写脚本不当的话,是非常浪费系统资源的。...
  • Shell 管道及执行顺序分析,需要的朋友可以参考下 1、基本概念  a、I/O重定向通常与 FD有关,shell的FD通常为10个,即 0~9;  b、常用FD有3个,为0(stdin,标准输入)、1(stdout,标准输出)、2(stderr,标准...
  • 利用swoole的定时器,每两秒检查一下 class Grep  {    const PORT = 9999;... $shell = "netstat -anp 2&gt;/dev/null | grep ". self::PORT ." | grep LISTEN | wc -l";  ...
  • 如何避免shell脚本被同时运行多次

    千次阅读 2017-06-22 15:14:08
    比如说有一个周期性(cron)备份mysql的脚本,或者rsync脚本, 如果出现意外,运行时间过长, 很有可能下一个备份周期已经开始了,当前周期的脚本却还没有运行完, ...显然我们都不愿意看到这样的情况发生。...
  • 我的机器学习教程「美团」算法工程师带你入门机器学习 已经开始更新了,欢迎大家订阅~ 任何关于算法、编程、AI行业知识或博客内容的问题,可以随时扫码关注公众号「图灵的猫」,加入”学习小组“,沙雕博主在线答疑...
  • 2019独角兽企业重金招聘Python工程师标准>>> ...
  • bash shell实现并发多进程操作

    千次阅读 2018-07-03 09:51:50
    前言目前我掌握的基本语言,php(最为熟悉,项目里代码都是用其实现),bash shell(运维利器),c(acm专用),这里面能实现多线程的貌似只有c,但是我c只是用来学习和实现算法和数据结构,因此工作中我想要模拟多...
  • 当我们在一个 shell 里运行一个脚本程序时,该 shell 就会 fork 出一个新进程,从而启动了另一个命令解释器(由脚本中第一行的 #!/bin/xxx 指定,如 bash shell)来解释运行我们这个脚本。也就是说,这个新进程是一...
  • shell编程

    2011-03-21 23:42:00
    作为命令语言,它交互式地解释和执行用户输入的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支。它虽然不是Linux系统核心的一部分,但它调用了系统...
  • Shell 进阶指南

    2017-07-15 19:25:38
    Awesome Shell 这是一份非常棒的命令行框架、工具包、指南、以及小玩意儿组织清单。由 awesome-php 获得灵感。该 awesome 收集在 Unix-Shell.ZEEF.com 上也可用。 命令行效率 定制 针对开发者 系统工具 下载与服务 ...
  • <p><strong><em>2nd Method with shell_exec that calls another script ( Doesnt work )</em></strong> <pre><code><?php shell_exec("php test.php"); ?> </code></pre> <p><em>And the test.php</em> ...
  • php不支持多线程,但是我们可以把问题转换成“多进程”来解决。由于php中的pcntl_fork...下面是一个例子:被并行调用的子程序代码:if($argc==1){echo("argv/n");}$arg = $argv[1];for($i=0; $i{echo($i.".1.".time().
1 2 3 4 5 ... 20
收藏数 6,043
精华内容 2,417
关键字:

php shell并行执行