你所不知道的linux匿名管道知识

相信很多在linux平台工作的童鞋, 都很熟悉管道符 ‘|‘, 通过它, 我们能够很灵活的将几种不同的命令协同起来完成一件任务。就好像下面的命令:

不过这次咱们不来说这些用法, 而是来探讨一些更加有意思的, 那就是 管道两边的数据流"实时性" 和 管道使用的小提示。

其实我们在利用管道的时候, 可能会不经意的去想, 我前一个命令的输出, 是全部处理完再通过管道传给第二个命令, 还是一边处理一边输出呢? 可能在大家是试验中或者工作经验中, 应该是左边的命令全部处理完再一次性交给右边的命令进行处理, 不光是大家, 我在最初接触管道时, 也曾有这么一个误会, 因为我们通过现象看到的就是这样。

但其实只要有简单了解过管道这工具, 应该都不难得出解释:

管道是两边是同时进行, 也就是说, 左边的命令输出到管道, 管道的右边将马上进行处理。

管道的定义

管道是由内核管理的一个缓冲区,相当于我们放入内存中的一个纸条。管道的一端连接一个进程的输出。这个进程会向管道中放入信息。管道的另一端连接一个进程的输入,这个进程取出被放入管道的信息。一个缓冲区不需要很大,它被设计成为环形的数据结构,以便管道可以被循环利用。当管道中没有信息的话,从管道中读取的进程会等待,直到另一端的进程放入信息。当管道被放满信息的时候,尝试放入信息的进程会堵塞,直到另一端的进程取出信息。当两个进程都终结的时候,管道也自动消失。

管道工作流程图

通过上面的解释可以看到, 假设 COMMAND1 | COMMAND2, 那么COMMAND1的标准输出, 将会被绑定到管道的写端, 而COMMAND2的标准输入将会绑定到管道的读端,  所以当COMMAND1一有输出, 将会马上通过管道传给COMMAND2, 我们先来做个实验验证下:

在上面的命令, 我们可以猜测下输出结果: 究竟是 睡眠6秒之后, 输出"1111222", 还是输出 "1111" 睡眠3秒, 再输出 "2222", 然后再睡眠3秒, 再输出"1111" 呢? 答案就是: 都不是! what! 这不可能, 大家可以尝试下, 我们会看到终端没反应了,  为什么呢? 这就要涉及到文件IO的缓冲方式了,这里不多说, 简单提一下文件IO的三种缓冲方式:

  • 全缓冲: 直到缓冲区被填满,才调用系统I/O函数, (一般是针对文件)
  • 行缓冲: 遇到换行符就输出(标准输出)
  • 无缓冲: 没有缓冲区,数据会立即读入或者输出到外存文件和设备上(标准错误

因为python是默认采用带缓冲的fputs, 又因为标准输出被改写到管道, 所以将会采取全缓冲的方式(shell 命令具体要看实现, 因为有些是用不带缓冲write实现,如果不带缓冲区,会直接写入管道), 所以将会采取全缓冲的方式, 也就是说, 直到缓冲区被填满, 或者手动显示调用flush刷入,才能看到输出。那我们可以将代码改写成下面两种方式吧

输出结果:

在这里我们已经能够得出结果, 如果像我们以前所想的那样, 要等到COMMAND1全部执行完才一次性输出给COMMAND2, 那么结果应该是无限堵塞。因为我的程序一直没有执行完。这样应该是不符合老前辈们设计初衷的, 因为这样可能会导致管道越来越大。然而管道也是有大小的~ 具体可以去看posix标准, 所以我们得出结论是: 只要COMMAND1的输出写入管道的写端(不管是缓冲区满还是手动flush), COMMAND2都将立刻得到数据并且马上处理。

那么 管道两边的数据流"实时性" 讨论到就先暂告一段落, 接下来将在这个基础上继续讨论: 管道使用的小提示。

在开始讨论前, 我想先引入一个专业术语, 也是我们偶尔会遇到的, 那就是: SIGPIPE。

或者是一个更加具体的描述: broken pipe (管道破裂)

上面的专业术语都是跟管道读写规则息息相关的, 那咱们来看下 管道的读写规则吧:

1.当没有数据可读时

  • O_NONBLOCK (未设置):read调用阻塞,即进程暂停执行,一直等到有数据来到为止。
  • O_NONBLOCK  ( 设置 ) :read调用返回-1,errno值为EAGAIN。

2.当管道满的时候

  • O_NONBLOCK (未设置): write调用阻塞,直到有进程读走数据
  • O_NONBLOCK ( 设置 ):调用返回-1,errno值为EAGAIN

3.如果所有管道写端对应的文件描述符被关闭,则read返回0

4.如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE

5.当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。

6.当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。

在上面我们可以看到, 如果我们收到SIGPIPE信号, 那么一般情况就是读端被关闭, 但是写端却依旧尝试写入

咱们来重现下 SIGPIPE

这次执行命令需要考验手速了, 因为我们要赶在py醒过来之前, 将读端进程杀掉

输出结果

从上图我们可以验证两个点:

  1. 当我们杀掉读端时, 写端会收到SIGPIPE而默认退出, 管道结束
  2. 当我们杀掉读端时, 写端的程序并不会马上收到SIGPIPE, 相反的, 只有真正写入管道写端时才会触发这个错误

如果写入一个 读端已经关闭的管道, 将会收到一个 SIGPIPE, 那读一个写端已经关闭的管道又会这样呢?

在上面也已经证明了上文提到的读写规则: 如果所有管道写端对应的文件描述符被关闭,将产生EOF结束标志,read返回0, 程序退出

总结

通过上面的理论和实验, 我们知道在使用管道时, 两边命令的数据传输过程, 以及对管道读写规则有了初步的认识, 希望我们以后在工作时, 再接触管道时, 能够更加有把握的去利用这一强大的工具。

文章来源:马哥教育

官方微信:马哥linux运维

技术交流群:537045784

时间: 2024-08-10 21:17:17

你所不知道的linux匿名管道知识的相关文章

你所不知道的html5与html中的那些事(二)

文章简介: 关于html5相信大家早已经耳熟能详,但是他真正的意义在具体的开发中会有什么作用呢?相对于html,他又有怎样的新的定义与新理念在里面呢?为什么一些专家认为html5完全完成后,所有的工作都可以达到真正的云方式呢?这一系列的问题你是否已经想明白了呢? 本系列文章将为您一一解答你所不知道的关于html5与html中的那些事;具体会包括如:html5新的理念与想法,html5的新标签的用意与具体开发中场景应用,html5与css3的感情经历(用法搭配),包括html5的父亲html的一些

你所不知道的SQL Server数据库启动过程(用户数据库加载过程的疑难杂症)

前言 本篇主要是上一篇文章的补充篇,上一篇我们介绍了SQL Server服务启动过程所遇到的一些问题和解决方法,可点击查看,我们此篇主要介绍的是SQL Server启动过程中关于用户数据库加载的流程,并且根据加载过程中所遇到的一系列问题提供解决方案. 其实SQL Server作为微软的一款优秀RDBMS,它启动的过程中,本身所带的那些系统库发生问题的情况相对还是很少的,我们在平常使用中,出问题的大部分集中于我们自己建立的用户数据库. 而且,相对于侧重面而言,其实我们更关注的是我们自己建立的用户数

你所不知道的JavaScript数组

你所不知道的JavaScript数组 相信每一个 javascript 学习者,都会去了解 JS 的各种基本数据类型,数组就是数据的组合,这是一个很基本也十分简单的概念,他的内容没多少,学好它也不是件难事情.但是本文着重要介绍的并不是我们往常看到的 Array,而是 ArrayBuffer. 我写的很多东西都是因为要完成某些特定的功能而刻意总结的,可以算是备忘,本文也是如此!前段时间一直在研究 Web Audio API 以及语音通信相关的知识,内容侧重于音频流在 AudioContext 各个

你所不知道的ref

在c#中有个关键字叫ref,它的作用是使参数按引用传递,基本用法如下: 1 class RefExample 2 { 3 static void Method(ref int i) 4 { 5 i = 44; 6 } 7 static void Main() 8 { 9 int val = 0; 10 Method(ref val); 11 // val is now 44 12 } 13 } 可见,关键字ref在使用的时候,在函数声明可函数调用的时候,在参数上必须添加ref,否则编译器就会提示

你所不知道的日志异步落库

在互联网设计架构过程中,日志异步落库,俨然已经是高并发环节中不可缺少的一环.为什么说是高并发环节中不可缺少的呢? 原因在于,如果直接用mq进行日志落库的时候,低并发下,生产端生产数据,然后由消费端异步落库,是没有什么问题的,而且性能也都是异常的好,估计tp99应该都在1ms以内.但是一旦并发增长起来,慢慢的你就发现生产端的tp99一直在增长,从1ms,变为2ms,4ms,直至send timeout.尤其在大促的时候,我司的系统就经历过这个情况,当时mq的发送耗时超过200ms,甚至一度有不少t

你所不知道的html5与html中的那些事(一)

分类: Web开发 文章简介: 关于html5相信大家早已经耳熟能详,但是他真正的意义在具体的开发中会有什么作用呢?相对于html,他又有怎样的新的定义与新理念在里面呢?为什么一些专家认为html5完全完成后,所有的工作都可以达到真正的云方式呢?这一系列的问题你是否已经想明白了呢? 本系列文章将为您一一解答你所不知道的关于html5与html中的那些事;具体会包括如:html5新的理念与想法,html5的新标签的用意与具体开发中场景应用,html5与css3的感情经历(用法搭配),包括html5

JavaScript你所不知道的困惑(2)

困惑一: var obj1 = new Object(); var obj2 = obj1; obj1.name = "阳光小强"; alert(obj2.name); //输出结果:阳光小强 JavaScript中的5个基本类型:Undefined.Null.Boolean.Number和String都是按值访问的,可以操作保存在变量中的实际的值,内存空间如下: var num1 = 5; var num2 = num1; 引用类型的值是保存在内存中的对象,JavaScript不允许

JavaScript你所不知道的困惑(1)

困惑一: 先看一个例子: function test(){ message = "hi"; } test(); alert(message); 会输出字符串"hi" 在函数内部使用var定义的变量是局部变量,省略var操作符的变量是全局变量. 困惑二: alert(undefined == null) 结果是"true" 我们知道在js中分为基本类型和引用类型,基本类型包括number.string.boolean.undefined.null.

你所不知道的html5与html中的那些事(四)——文本标签

文章简介: 关于html5相信大家早已经耳熟能详,但是他真正的意义在具体的开发中会有什么作用呢?相对于html,他又有怎样的新的定义与新理念在里面呢?为什么一些专家认为html5完全完成后,所有的工作都可以达到真正的云方式呢?这一系列的问题你是否已经想明白了呢? 本系列文章将为您一一解答你所不知道的关于html5与html中的那些事;具体会包括如:html5新的理念与想法,html5的新标签的用意与具体开发中场景应用,html5与css3的感情经历(用法搭配),包括html5的父亲html的一些