1. 程式人生 > >shell多進程實例

shell多進程實例

shell多進程 文件描述符 管道

shell 多進程基礎
  • 代碼塊:用 { } 囊括,作為一個整體
  • &作用:將命令放於後臺處理,空閑出當前控制臺以用於做其他操作
  • wait命令:等待父進程的子進程都執行結束後再執行父進程中的指令
  • trap命令:獲取控制信號,並作出處理;格式:trap CAMMANDS SIGNAL
  • 通過exec執行:創建一個新的同PID的進程去處理,變量共用,執行完exec內容後,不回到原來的調用
  • 通過fork執行:創建新進程(子進程)處理,變量只能單向傳遞
  • 通過source執行:加載到同一進程,在同一控制臺串行處理,變量共用,執行完source內容後,再回到原來的地方接著處理

多進程關鍵點

  1. 文件描述符:

    是一個索引值,是內核為每一個進程與進程所打開的文件的一個映射記錄表。當程序打開一個現有文件或者創建一個新文件時,內核向進程返回一個文件描述符。
    文件與描述符關系:每一個文件描述符會對應一個打開文件;不同的文件描述符可以對應同一個打開文件;同一個文件可以被不同的進程打開,也可以被同一個進程多次打開。
    默認描述符:/proc/self/fd (0,1,2)
    自定義描述符:
    可用範圍:ulimit -n 查看,再除去默認的0,1,2

  2. 管道:類似於隊列
    特點:
    對管道的讀寫操作應同時進行,不然操作就會被滯留
    按行為單位進行操作
    匿名管道:常用的“|”,前一個命令的標準輸出作為下一個命令的標準輸入
    有名管道:一般作為任務隊列,有序存取
    使用mkfifo命令創建一個有名管道

3.管道與文件描述符關聯

mkfifo  /tmp/$$.fifo
exec 5 <>/tmp/$$.fifo
rm -f /tmp/$$.fifo

文件描述符與管道綁定:解決管道讀寫必須同時存在的特性
刪除管道:系統調用exec是以新的進程去代替原來的進程,但進程的PID保持不變

多進程實例

mysql分庫備份

#!/bin/bash
hour=`date +%H`
day=`date +%F`
now=`date +%F_%H`
all_dbs="no"
passwd="mysql_pass"
sshpass="ssh_pass"
dbs="db1 db2 db3 dbx dby dbz"

cpu_num=`cat /proc/cpuinfo |grep processor|wc -l`
p_fifo="/tmp/$$.pipo"
mkfifo $p_fifo
exec 111<>$p_fifo       #關聯文件描述符和管道
rm -f $p_fifo
trap "exec 111>&-;exec 111<&-;exit 0" 2    
for ((i=1; i<=$cpu_num; i++))
do
    echo >&111             #定義進程隊列大小,cpu核數
done

function backup()
{
    if [ $all_dbs == "no" ];then
        for db in $dbs
        do
            read -u111      #從隊列中獲取一個消息,隊列中消息數減一
            {
            dbname=`echo $db|sed "s/-/@002d/g"`
            ops="--parallel=5 --compress-threads=5 --databases=$dbname"
            bpath="/data1/ehr-mysql-backup/${day}/${db}"
            inbackup
            sleep 10
            echo >&111  #添加一個消息到隊列中,維持隊列中消息數不變(進程個數)
            } &               #將代碼塊放後臺處理
        done
        wait                 #等待所有後臺進程處理完
        exec 111>&-   #關閉描述符,讀寫分開關閉
        exec 111<&-
    else
        ops="--parallel=5 --compress-threads=5"
        bpath="/data1/ehr-mysql-backup/${day}"
        inbackup
    fi
}

function inbackup()
{ 
    if [ -f ${bpath}/lsn_${last}/xtrabackup_checkpoints ];then
        echo "incremental_basedir found,do a increment backup"
        /usr/bin/innobackupex -u root -p${passwd} --no-timestamp ${ops} --incremental --incremental_basedir=${bpath}/lsn_${last}/ --extra-lsndir=${bpath}/lsn_${now}/ ${bpath} --stream=xbstream |gzip |sshpass -p "${sshpass}" ssh -p 18122 [email protected] "cat - > ${bpath}/${now}.xbstram.gz"
    else
        echo "incremental_basedir not found,do a full backup"
        /usr/bin/innobackupex -u root -p${passwd} --no-timestamp ${ops} --extra-lsndir=${bpath}/lsn_${now}/ ${bpath} --stream=tar |gzip |sshpass -p "${sshpass}" ssh -p 18122 [email protected] "cat - > ${bpath}/${now}.tgz"
    fi

}

case $hour in
22)
        last=`date +%F -d -yesterday`
        find /data1/ehr-mysql-backup/ -name "${last}*" -type d -exec rm -r "{}" \;
        day=`date +%F -d +1days`
        backup
        ;;
10)
        last=`date +%F_%H -d -12hours`
        backup
        ;;
14|18)
        last=`date +%F_%H -d -4hours`
        backup
        ;;
*)
        echo "not backup time"
        ;;
esac

shell多進程實例