• shell模拟“多线程”


      shell中并没有真正意义上的多线程,要实现“多线程”可以启动多个子进程,并将子进程放入后台执行来模拟多线程,最大程度利用CPU性能。

    循环中执行并行代码

    #!/bin/bash
    date
    for i in `seq 1 5`
    do
    {
    	echo "sleep 5"
    	sleep 5
    } &
    done
    wait
    date
    

    执行结果如下:
    Thu Oct 19 19:58:43 CST 2017 sleep 5 sleep 5 sleep 5 sleep 5 sleep 5 Thu Oct 19 19:58:48 CST 2017
    由此我们可以看出,所有的for循环下的指令都可以同时执行,使用wait命令等待所有子进程结束。

      这样能够提供脚本运行的效率,但是我们又不能无限制的让这个for循环去启动子进程,所以就需要我们对这个进程数进行设置。

    #!/bin/bash
    date
    trap "exec 5>&-; exec 5 <&-; exit 0" 2
    THREAD_NUM=10
    tmp_fifofile="/tmp/$$.fifo"
    mkfifo "$tmp_fifofile"
    exec 5<>"$tmp_fifofile"
    rm $tmp_fifofile
    for ((i=0;i<$THREAD_NUM;i++));do
        echo
    done >&5
    
    for i in `seq 1 50`
    do
        read -u5
        {
            sleep 1
    	echo "----------"
            echo >&5
        } &
    done
    wait
    exec 5>&-
    date
    

    trap "exec 5>&-; exec 5 <&-; exit 0" 2#接收信号2(Ctrl +C )的操作,并关闭描述符5
    THREAD_NUM=10#允许的最大进程数。
    tmp_fifofile="/tmp/$$.fifo"#以脚本运行的当前进程ID号作为文件名。
    mkfifo "$tmp_fifofile"#新建一个随机FIFO管道文件。
    exec 5<>"$tmp_fifofile"#定义文件描述符5指向这个FIFO管道文件(对文件描述符5的所有操作等同于对管道文件)。
    rm $tmp_fifofile#删除管道文件,删除与否都无所谓。

        echo
    done >&5```#使用一个for循环向管道中输入$THREAD_NUM个空行;>符号为输出重定向;&符号表示5为文件描述符,也就是说&5表示文件描述符5。
    `read -u5`#表示从文件描述符5(管道)中读取行,每次读一行,如果读完了就会挂起,直到管道中再次有可读的行。
    `echo >&5`#再次向管道中写入空行,避免挂起的for循环停止执行。
    `} &`#将进程放到后台,表明for循环中的`sleep 1`与`----------`这两条指令有10个进程在后台同时执行
    `wait`等待所有进程执行完成
    `exec 5>&-`#删除文件描述符5
    
    ### 关联详解
    #### Linux文件描述符
    &nbsp; 文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于UNIX、Linux这样的操作系统。
    &nbsp; 每个Unix进程(除了可能的守护进程)应均有三个标准的POSIX文件描述符,对应于三个标准流:
    | 整数值 | 名称 | <unistd.h>符号常量 | <stdio.h>文件流 |
    |----|----|----|----|
    |0|Standard input|STDIN_FILENO|stdin
    |1|Standard output|STDOUT_FILENO|stdout
    |2|Standard error|STDERR_FILENO|stderr
    &nbsp; 我们可以使用exec指令自行定义、绑定文件描述符,文件描述符一般从3~(n-1)可以使用,n=ulimit -n的数值。
    #### 管道
    &nbsp; Linux管道包含两种
    - 匿名管道
    - 命名管道
    
    &nbsp; 管道有一个特点,如果管道中没有数据,那么取管道数据的操作就会滞留,直到管道内进入数据,然后读出后才会终止这一操作;同理,写入管道的操作如果没有读取管道的操作,这一动作就会滞留。
    ##### 匿名管道
    &nbsp; 在Unix或类Unix操作系统的命令行中,匿名管道使用ASCII中垂直线|作为匿名管道符,匿名管道的两端是两个普通的,匿名的,打开的文件描述符:一个只读端和一个只写端,这就让其它进程无法连接到该匿名管道。
    ##### 命名管道
    &nbsp; 命名管道也称FIFO,从语义上来讲,FIFO其实与匿名管道类似,但值得注意:
    - 在文件系统中,FIFO拥有名称,并且是以设备特俗文件的形式存在的;
    - 任何进程都可以通过FIFO共享数据;
    - 除非FIFO两端同时有读与写的进程,否则FIFO的数据流通将会阻塞;
    - 匿名管道是由shell自动创建的,存在于内核中;而FIFO则是由程序创建的(比如mkfifo命令),存在于文件系统中。
  • 相关阅读:
    JS-排序详解-选择排序
    JS-排序详解-快速排序
    JS-排序详解-冒泡排序
    正则表达式入门
    JS-最全的创建对象的方式
    用JS实现回文数的精准辨别!!!
    基本包装类型
    引用类型之Function类型
    引用类型之Array类型
    Object类型
  • 原文地址:https://www.cnblogs.com/Cherry-Linux/p/7699001.html
Copyright © 2020-2023  润新知