0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

管道数据流"实时性" 和使用小提示

Linux爱好者 来源:YXQ 2019-08-09 17:36 次阅读

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

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

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

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

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

管道的定义

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

管道工作流程图

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

#1.pyimporttimeimportsyswhile1:print'1111'time.sleep(3)print'2222'time.sleep(3)
[root@iZ23pynfq19Z~]#python1|cat

在上面的命令, 我们可以猜测下输出结果: 究竟是 睡眠6秒之后, 输出"1111222", 还是输出 "1111" 睡眠3秒, 再输出 "2222", 然后再睡眠3秒, 再输出"1111" 呢? 答案就是: 都不是! what! 这不可能, 大家可以尝试下, 我们会看到终端没反应了, 为什么呢? 这就要涉及到文件IO的缓冲方式了,关于文件IO, 可以参考我的另一篇文章:浅谈文件描述符1和2, 在最下面的地方提到文件IO的三种缓冲方式:

全缓冲:直到缓冲区被填满,才调用系统I/O函数, (一般是针对文件)

行缓冲: 遇到换行符就输出(标准输出)

无缓冲:没有缓冲区,数据会立即读入或者输出到外存文件和设备上(标准错误

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

#方式1:填满缓冲区,我这边大小是4096字节,你们也可以试下这个值,估计都一样importtimeimportsyswhile1:print'1111'*4096time.sleep(3)print'2222'*4096time.sleep(3)#方式2:手动刷入写队列importtimeimportsyswhile1:print'1111'sys.stdout.flush()//因为是标准输出,所以直接通过sys的接口去flushtime.sleep(3)print'2222'sys.stdout.flush()time.sleep(3)

输出结果:


#第一种方式:[root@iZ23pynfq19Z~]#python1|cat1111.....(超多1,刷屏了..)睡眠3秒..2222.....(超多2,刷屏了..)#第二种方式:[root@iZ23pynfq19Z~]#python1|cat1111睡眠3秒..2222睡眠3秒..1111....

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

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

在开始讨论前, 我想先引入一个专业术语, 也是我们偶尔会遇到的, 那就是:SIGPIPE或者是一个更加具体的描述:broken pipe (管道破裂)

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

当没有数据可读时

O_NONBLOCK (未设置):read调用阻塞,即进程暂停执行,一直等到有数据来到为止。

O_NONBLOCK ( 设置 ) :read调用返回-1,errno值为EAGAIN。

当管道满的时候

O_NONBLOCK (未设置):write调用阻塞,直到有进程读走数据

O_NONBLOCK ( 设置 ):调用返回-1,errno值为EAGAIN

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

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

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

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

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

咱们来重现下SIGPIPE

#!/usr/bin/pythonimporttimeimportsyswhile1:time.sleep(10)#手速不够快的童鞋可以将睡眠时间设置长点print'1111'sys.stdout.flush()

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

python1|cat------------------------#另一个终端[root@iZ23pynfq19Z~]#ps-fe|grep-P'cat|python'root107754074000:05pts/200:00:00python1root107764074000:05pts/200:00:00cat#读端进程root1083332581000:06pts/000:00:00grep-Pcat|python[root@iZ23pynfq19Z~]#kill10776

输出结果

[root@iZ23pynfq19Z~]#python1|catTraceback(mostrecentcalllast):File"1",line6,insys.stdout.flush()IOError:[Errno32]BrokenpipeTerminated

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

当我们杀掉读端时, 写端会收到SIGPIPE而默认退出, 管道结束

当我们杀掉读端时, 写端的程序并不会马上收到SIGPIPE, 相反的, 只有真正写入管道写端时才会触发这个错误

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

importtimeimportsys#这次我们不需要死循环,因为我们想要写端快点关闭退出time.sleep(5)print'1111'sys.stdout.flush()
#因为我们想要读端等到足够长的时间,让写端关闭,所以我们需要利用awk先睡眠10秒[root@iZ23pynfq19Z~]#python1.py|awk'{system("sleep10");print123}'------------------------[root@iZ23pynfq19Z~]#ps-fe|grep-P'awk|python'root117174074000:20pts/200:00:00python1.pyroot117184074000:20pts/200:00:00awk{system("sleep10");print123}root1172132581000:20pts/000:00:00grep-Pawk|python#5秒过后[root@iZ23pynfq19Z~]#ps-fe|grep-P'awk|python'root116854074000:20pts/200:00:00awk{system("sleep10");print123}root1169832581000:20pts/000:00:00grep-Pawk|python#10秒过后[root@iZ23pynfq19Z~]#python1|awk'{system("sleep10");print123}'123

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

总结

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

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    87

    文章

    11302

    浏览量

    209434
  • 管道
    +关注

    关注

    3

    文章

    145

    浏览量

    17972

原文标题:聊聊 Linux 的匿名管道

文章出处:【微信号:LinuxHub,微信公众号:Linux爱好者】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    大众数据流分析

    、3.0发动机数据流定义与解释别克君威2.0发动机数据流定义与解释凯越数据流列表凯越发动机数据流定义赛欧数据流列表赛欧
    发表于 06-15 12:28

    探测小提示

    选择满足示波器和应用需求的探头,可以使您能够进行必要的测量。实际上,进行测量和获得有用的结果还取决于怎样使用工具。下面的探测小提示将有助于您避免某些常见的测量问题。补偿探头大多数探头是为与特定
    发表于 12-17 17:12

    部署实时数据流平台面临的挑战有哪些?

    部署实时数据流平台面临的五大挑战
    发表于 03-17 07:00

    LabVIEW数据流控制方法研究

    本文剖析了LabVIEW 数据流语言的特点,提供了其若干有效控制方法,指出LabVIEW 本身即可解决数据流控制上的变量冲突、响应时序控制、初始状态自适应调整等问题并保证其通用
    发表于 07-30 11:39 13次下载

    基于数据流的Java字节码分析

    本文基于数据流框架理论,提出了如何将数据流分析方法应用于JAVA 字节码中,通过建立数据流与半格、数据流和函数调用图的关系,从而对类型信息进行分析。实验表明该
    发表于 12-25 13:22 9次下载

    网络数据流存储算法分析与实现

    针对网络数据流存储的瓶颈问题,提出了一种网络数据流存储算法分析与实现方法,仿真结果表明,模型能显著提高网络数据流实时存储能力
    发表于 05-26 15:57 21次下载
    网络<b class='flag-5'>数据流</b>存储算法分析与实现

    基于FPGA芯片的数据流结构分析

    的兼容。 这里详细介绍了Virtex 系列FPGA 芯片的数据流大小及结构。Virtex支持一些新的非常强大的配置模式,包括部分重新配置,这种配置机制被设计到高级应用中,以便通过芯片的配置接口能够访问及操作片内数据。但想要配置
    发表于 11-18 11:37 2335次阅读

    数据流编程模型优化

    数据流编程模型将程序的计算与通信分离,暴露了应用程序潜在的并行并简化了编程难度。分布式计算框架利用廉价PC构建多核集群解决了大规模并行计算问题,但多核集群层次存储结构和处理单元对数据流
    发表于 11-23 15:48 3次下载
    <b class='flag-5'>数据流</b>编程模型优化

    数据环境下的分布式数据流处理关键技术探析

    数据环境下的数据流处理实时性要求高,数据计算要求持续和高可靠。分布式
    发表于 12-05 19:04 0次下载
    大<b class='flag-5'>数据</b>环境下的分布式<b class='flag-5'>数据流</b>处理关键技术探析

    数据流的网络实时入侵检测

    针对计算机网络访问请求具有实时到达以及动态变化的特点,为了实时检测网络入侵,并且适应网络访问数据的动态变化,提出一个基于数据流的网络入侵实时
    发表于 01-17 10:09 0次下载
    <b class='flag-5'>数据流</b>的网络<b class='flag-5'>实时</b>入侵检测

    时间数据流的并行检测算法

    针对现有长持续时间数据流检测算法的实时差、检测精度与估计精度低的问题,提出长持续时间数据流的并行检测算法。基于共享数据结构的长持续时间
    发表于 03-06 15:54 0次下载
    时间<b class='flag-5'>数据流</b>的并行检测算法

    数据流是什么

    数据流最初是通信领域使用的概念,代表传输中所使用的信息的数字编码信号序列。然而,我们所提到的数据流概念与此不同。这个概念最初在1998年由Henzinger在文献87中提出,他将数据流定义为“只能以事先规定好的顺序被读取一次的
    的头像 发表于 02-27 15:25 7088次阅读

    控制数据流的区别

    控制数据流的区别  在计算机科学中,控制数据流是两个非常重要的概念。虽然它们经常一起使用,但它们具有非常不同的含义。本文将讨论控制
    的头像 发表于 09-13 11:17 5571次阅读

    示波器探头的探测小提示

    选择满足示波器和应用需求的探头,可以使您能够进行必要的测量。实际上,进行测量和获得有用的结果还取决于怎样使用工具。下面的探测小提示将有助于您避免某些常见的测量问题: 补偿探头 大多数探头是为与特定
    的头像 发表于 07-23 10:53 217次阅读
    示波器探头的探测<b class='flag-5'>小提示</b>

    理解ECU数据流的分析方法

    随着汽车电子化程度的提高,ECU在车辆中扮演的角色越来越重要。它们不仅控制着发动机管理、变速箱、制动系统等关键功能,还涉及到车辆的舒适和安全。 ECU数据流分析的重要 故障诊断
    的头像 发表于 11-05 11:07 413次阅读