4

shell以及find的多线程执行

 2 years ago
source link: https://zhangrr.github.io/posts/20211029-bash_multithread/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Shell以及find的多线程执行

2021-10-29 2 分钟阅读

这属于Shell的高级技巧了,我们可能需要在 bash 中并发 wget rsync 文件,下面就讨论一下这个问题。

首先从简单的单线程开始:

$ for i in $(seq 1 2); do echo $i; done
1
2
shell

可以看到是顺序执行的,下面变多线程:

$ for i in $(seq 1 2); do echo $i & done
[1] 245505
1
[2] 245506
2
[1]   Done                    echo $i
[2]   Done                    echo $i
shell

可以看到我们只把 ; 号改成了 & 号,程序就变成了多线程执行。

区别在于 ; 号会等待之前的命令执行完毕再执行下一条,而 & 不等待,直接继续执行下一条;相当于后台运行了前一条命令。

下面说说 find 的单线程和多线程:

find 的 exec 用法

$ find /path [args] -exec [cmd] {} \;
shell
  • {} 占位符号,存放find找到的记录
  • ; 对于每一条找到的单独记录,执行的cmd是一条一条单独执行的
  • 执行的顺序如下: cmd result1; cmd result2; …; cmd result N
$ find /path [args] -exec [cmd] {} \+
shell
  • {} 占位符号,存放find找到的记录
  • + 对于找到的所有记录,执行的cmd是合并了所有记录集执行的
  • 执行顺序如下: cmd result1 result2 … result N

多个exec可以串起来:

$ find /tmp/dir1/ -type f -exec grep howtouselinux {} \; -exec echo {} \; | sed  's/howtouselinux/deep/g'
shell

至此,find 也还是单线程执行的,并没有并发。

find 要并发,就只能跟 xargs 结合在一起:

xargs 通常配合管道使用,将前面命令产生的参数,逐个传入后续命令,作为参数。xargs 传来的参数,默认位于 xargs 后面命令的最后,如果要改变位置,需要用**-I**参数。xargs 如果不带命令,缺省是 echo

  • -d 分隔符

    $ echo -e "a\tb\tc" | xargs -d "\t" echo
    a b c
    
  • -I{} 指定占位符,-I %那就是 % 替代从之前管道取得的参数

    $ find . -type d | xargs -I % -0 rsync -auvPR % 192.168.1.38::new/
    
  • -0 跟find的-print0配合,find命令有一个特别的参数-print0,指定输出的文件列表以null分隔。然后,xargs命令的-0参数表示用null当作分隔符。

    $ find ./new -mindepth 6 -maxdepth 6 -type d -print0 | xargs -I % -0 rsync -auvPR % 172.18.34.38::new/
    
  • -P 最大并发线程数,下面是并发30线程

    $ find ./new -mindepth 6 -maxdepth 6 -type d -print0 | xargs -P 30 -I % -0 rsync -auvPR % 172.18.34.38::new/
    
  • -n 选项限制单个命令行的参数个数,下面是 rsync 一行命令传带60个文件,30个进程那就是30个 rsync,每个 rsync 同时传60个文件。

    $ find ./new -mindepth 6 -maxdepth 6 -type d -print0 | xargs -P 30 -n 60 -I % -0 rsync -auvPR % 172.18.34.38::new/
    
    $ echo {0..10} | xargs -I{} -n 2
    0 1
    2 3
    4 5
    6 7
    8 9
    10
    

使用 bash -c 并发的例子:

$ time for i in $(seq 1 5); do echo $[$RANDOM % 5 + 1]; done | xargs -I{} echo "sleep {}; echo 'Done! {}'" | xargs -P5 -I{} bash -c "{}"
shell

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK