热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

取文件shell_理解Shell脚本中的多进程和多线程并发,让工作效率提升1000倍

背景日常运维工作中编写shell脚本处理事务,很多时候需要一次性处理很多,需要用到循环,但是循环体内还是线性的,还是要一个个

背景

日常运维工作中编写shell脚本处理事务,很多时候需要一次性处理很多,需要用到循环,但是循环体内还是线性的,还是要一个个处理,这样并不会节省很多时间,只是节省了人工一次次输入的繁琐。但是对于提高处理能力,没有实质性的提高。这就需要考虑并发。但Shell中并没有真正意义的多线程,要实现多线程可以启动多个后端进程,最大程度利用cpu性能。即:多进程并发,本篇教程由浅入深详细介绍了shell中的多进程并发。

8221bde22d0986233c5e1be9a69b6cdb.png

范例

#!/bin/bashtrap "exec 1000>&-;exec 1000testfiform -fr testfifofor((n&#61;1;n<&#61;10;n&#43;&#43;))do echo >&1000donestart&#61;&#96;date "&#43;%s"&#96;for((i&#61;1;i<&#61;100;i&#43;&#43;))do read -u1000 { echo "success $i"; sleep 5 echo >&1000 }&donewaitend&#61;&#96;date "&#43;%s"&#96;echo "Time: &#96;expr $end - $start&#96;"exec 1000>&-exec 1000

实验

所谓的多进程只不过是将多个任务放到后台执行而已&#xff0c;很多人都用到过&#xff0c;所以现在讲的主要是控制&#xff0c;而不是实现。

实验一

先看一个小shell&#xff1a;

06e17bf99ff7411bd9106e5719b125dc.png

看执行结果&#xff1a;

295256af1d45d111c9ebdb412517fa43.png

很明显是8s&#xff0c;这种不占处理器却有很耗时的进程&#xff0c;我们可以通过一种后台运行的方式
来达到节约时间的目的。

实验二

如下为改进&#xff1a;

4d6c1caddd32ddf20ffdb366a7b0574b.png

用“{}”将主执行程序变为一个块&#xff0c;用&放入后台&#xff0c;四次执行全部放入后台后&#xff0c;我们需要用一个wait指令&#xff0c;等待所有后台进程执行结束&#xff0c;不然 系统是不会等待的&#xff0c;直接继续执行后续指令&#xff0c;知道整个程序结束。
看结果&#xff1a;

7f1fde4494587f26f3675cc81f6d2328.png

可以看到&#xff0c;时间已经大大缩短了&#xff01;

实验三

以上实验虽然达到了多线程并发的目的&#xff0c;但有一个缺陷&#xff0c;不能控制运行在后台的进程数。为了控制进程&#xff0c;我们引入了管道 和文件操作符。

无名管道&#xff1a; 就是我们经常使用的 例如&#xff1a; cat text | grep “abc” 那个“|”就是管道&#xff0c;只不过是无名的&#xff0c;可以直接作为两个进程的数据通道
有名管道&#xff1a; mkfilo 可以创建一个管道文件 &#xff0c;例如&#xff1a; mkfifo fifo_file

管道有一个特点&#xff0c;如果管道中没有数据&#xff0c;那么取管道数据的操作就会停滞&#xff0c;直到管道内进入数据&#xff0c;然后读出后才会终止这一操作&#xff0c;同理&#xff0c;写入管道的操作&#xff0c;如果没有读取操作&#xff0c;这一个动作也会停滞。

ab545d65247e3849821799826adf8258.png

当我们试图用echo想管道文件中写入数据时&#xff0c;由于没有任何进程在对它做读取操作&#xff0c;所以它会一直停留在那里等待读取操作&#xff0c;此时我们在另一终端上用cat指令做读取操作

4424b80a9ff12cc9c07b194eec4fdbc5.png

你会发现读取操作一旦执行&#xff0c;写入操作就可以顺利完成了&#xff0c;同理&#xff0c;先做读取操作也是一样的&#xff1a;

04f71c3b8c4db7fcbff55d44628a5317.png

由于没有管道内没有数据&#xff0c;所以读取操作一直滞留在那里等待写入的数据

91e061bb33e71769770640c9055a627a.png

一旦有了写入的数据&#xff0c;读取操作立刻顺利完成

以上实验&#xff0c;看以看到&#xff0c;仅仅一个管道文件似乎很难实现 我们的目的(控制后台线程数), 所以 接下来介绍 文件操作符&#xff0c;这里只做简单的介绍&#xff0c;如果不熟悉的可以自行查阅资料。
系统运行起始&#xff0c;就相应设备自动绑定到了 三个文件操作符 分别为 0 1 2 对应 stdin &#xff0c;stdout&#xff0c; stderr 。
在 /proc/self/fd 中 可以看到 这三个三个对应文件

c71e765e8e08c57c63c0cf771c071a95.png

输出到这三个文件的内容都会显示出来。只是因为显示器作为最常用的输出设备而被绑定。

我们可以exec 指令自行定义、绑定文件操作符&#xff0c;文件操作符一般从3–(n-1)都可以随便使用
此处的n 为 ulimit -n 的定义值得

3e2a561ea6540d1d71fc365e8054ecba.png

可以看到 我的 n值为1024 &#xff0c;所以文件操作符只能使用 0-1023&#xff0c;可自行定义的 就只能是 3-1023 了。

直接上代码&#xff0c;然后根据代码分析每行代码的含义&#xff1a;

89b609d8758befea0e9373748963346c.png

代码解释

第3行&#xff1a; 接受信号 2 (ctrl &#43;C)做的操作。exec 1000>&-和exec 1000testfifo 来实现&#xff0c;但关闭时必须分开来写&#xff0c;> 读的绑定&#xff0c;<标识写的绑定 <> 则 标识 对文件描述符 1000的所有操作等同于对管道文件testfifo的操作。

第5-7行&#xff1a;分别为 创建管道文件&#xff0c;文件操作符绑定&#xff0c;删除管道文件
     可能会有疑问&#xff0c;为什么不能直接使用管道文件呢&#xff1f; 
     事实上&#xff0c;这并非多此一举&#xff0c;刚才已经说明了管道文件的一个重要特性了&#xff0c;那就是读写必须同时存在
     缺少某一种操作&#xff0c;另一种操作就是滞留&#xff0c;而绑定文件操作符 正好解决了这个问题。

第9-12 行&#xff1a; 对文件操作符进行写入操作。通过一个for循环写入10个空行&#xff0c;这个10就是我们要定义的后台线程数 量。
为什么写入空行而不是10个字符呢 &#xff1f;
这是因为&#xff0c;管道文件的读取 是以行为单位的。

39001ae8f1c725df30c820252a247cdf.png

当我们试图用 read 读取管道中的一个字符时&#xff0c;结果是不成功的&#xff0c;而刚才我们已经证实使用cat是可以 读取的。

第17-24行&#xff1a;这里假定我们有100个任务&#xff0c;我们要实现的时 &#xff0c;保证后台只有10个进程在同步运行 。read -u1000 的 作用是&#xff1a;读取一次管道中的一行&#xff0c;在这儿就是读取一个空行。减少操作附中的一个空行之后&#xff0c;执行一 次任务(当然是放到后台执行)&#xff0c;需要注意的是&#xff0c;这个任务在后台执行结束以后会向文件操作符中写 入一个空行&#xff0c;这就是重点所在&#xff0c;如果我们不在某种情况某种时刻向操作符中写入空行&#xff0c;那么结果就 是&#xff1a;在后台放入10个任务之后&#xff0c;由于操作符中没有可读取的空行&#xff0c;导致 read -u1000 这儿 始终停顿。

后边的 就不用解释了。

贴下执行结果&#xff1a;

2d744765b35156d17aa25196fbf9181b.png

每次的停顿中都能看到 只有10个进程在运行
一共耗时50s 一共100个任务&#xff0c;每次10个 &#xff0c;每个5s 正好50s。上边的结果图之所以这么有规律&#xff0c;这是因为我们所执行的100个任务耗时都是相同的。

比如&#xff0c;系统将第一批10个任务放入后台的过程所消耗的时间 几乎可以忽略不计&#xff0c;也就是说这10个任务几乎可以任务是同时运行&#xff0c;当然也就可以认为是同时结束了&#xff0c;而按照刚才的分析&#xff0c;一个任务结束时就会向文件描述符写入空行&#xff0c;既然是同时结束的&#xff0c;那么肯定是同时写入的空行&#xff0c;所以下一批任务又几乎同时运行&#xff0c;如此循环下去的。实际应用时&#xff0c;肯定不是这个样子的&#xff0c;比如&#xff0c;第一个放到后台执行的任务&#xff0c;是最耗时间的&#xff0c;那他肯定就会是最后一个执行完毕。所以&#xff0c;实际上来说&#xff0c;只要有一个任务完成&#xff0c;那么下一个任务就可以被放到后台并发执行了。



推荐阅读
  • 本文总结了Linux下多线程执行shell脚本的4种方法,包括切换到工作目录执行、使用绝对路径执行、直接使用bash或sh执行。同时介绍了为什么需要加上"./"来执行脚本的原因。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • ejava,刘聪dejava
    本文目录一览:1、什么是Java?2、java ... [详细]
  • 基于事件驱动的并发编程及其消息通信机制的同步与异步、阻塞与非阻塞、IO模型的分类
    本文介绍了基于事件驱动的并发编程中的消息通信机制,包括同步和异步的概念及其区别,阻塞和非阻塞的状态,以及IO模型的分类。同步阻塞IO、同步非阻塞IO、异步阻塞IO和异步非阻塞IO等不同的IO模型被详细解释。这些概念和模型对于理解并发编程中的消息通信和IO操作具有重要意义。 ... [详细]
  • 如何在服务器主机上实现文件共享的方法和工具
    本文介绍了在服务器主机上实现文件共享的方法和工具,包括Linux主机和Windows主机的文件传输方式,Web运维和FTP/SFTP客户端运维两种方式,以及使用WinSCP工具将文件上传至Linux云服务器的操作方法。此外,还介绍了在迁移过程中需要安装迁移Agent并输入目的端服务器所在华为云的AK/SK,以及主机迁移服务会收集的源端服务器信息。 ... [详细]
  • 本文介绍了Linux Shell中括号和整数扩展的使用方法,包括命令组、命令替换、初始化数组以及算术表达式和逻辑判断的相关内容。括号中的命令将会在新开的子shell中顺序执行,括号中的变量不能被脚本余下的部分使用。命令替换可以用于将命令的标准输出作为另一个命令的输入。括号中的运算符和表达式符合C语言运算规则,可以用在整数扩展中进行算术计算和逻辑判断。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • RouterOS 5.16软路由安装图解教程
    本文介绍了如何安装RouterOS 5.16软路由系统,包括系统要求、安装步骤和登录方式。同时提供了详细的图解教程,方便读者进行操作。 ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了软件测试知识点之数据库压力测试方法小结相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • linux进阶50——无锁CAS
    1.概念比较并交换(compareandswap,CAS),是原⼦操作的⼀种,可⽤于在多线程编程中实现不被打断的数据交换操作࿰ ... [详细]
  • Tomcat安装与配置教程及常见问题解决方法
    本文介绍了Tomcat的安装与配置教程,包括jdk版本的选择、域名解析、war文件的部署和访问、常见问题的解决方法等。其中涉及到的问题包括403问题、数据库连接问题、1130错误、2003错误、Java Runtime版本不兼容问题以及502错误等。最后还提到了项目的前后端连接代码的配置。通过本文的指导,读者可以顺利完成Tomcat的安装与配置,并解决常见的问题。 ... [详细]
  • ZABBIX 3.0 配置监控NGINX性能【OK】
    1.在agent端查看配置:nginx-V查看编辑时是否加入状态监控模块:--with-http_stub_status_module--with-http_gzip_stat ... [详细]
  • systemd-nspawn可以创建最轻量级的容器(ns的意思就是namespace),本文的实验平台是Ubuntu16.04,x86_64机器。本文的目的是:在Ubuntu中用syst ... [详细]
author-avatar
手机用户2602915205
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有