<th id="ik4gr"><pre id="ik4gr"></pre></th>
<rp id="ik4gr"></rp>
    <dd id="ik4gr"></dd>

  1. <rp id="ik4gr"><object id="ik4gr"><blockquote id="ik4gr"></blockquote></object></rp>
      <rp id="ik4gr"></rp>
        <button id="ik4gr"><acronym id="ik4gr"></acronym></button>
      1. <rp id="ik4gr"><object id="ik4gr"><input id="ik4gr"></input></object></rp>
        1. 杭州嵌入式培訓
          達內杭州嵌入式培訓中心

          13175137725

          Linux的匿名管道你了解多少

          • 時間:2019-06-28 11:28
          • 發布:轉載
          • 來源:網絡

          相信很多在Linux平臺工作的童鞋,都很熟悉管道符'|',通過它,我們能夠很靈活的將幾種不同的命令協同起來完成一件任務.就好像下面的命令:

          echo 123 | awk '{print $0+123}' # 輸出246

          不過這次咱們不來說這些用法,而是來探討一些更加有意思的,那就是 管道兩邊的數據流"實時性" 和 管道使用的小提示.

          其實我們在利用管道的時候,可能會不經意的去想,我前一個命令的輸出,是全部處理完再通過管道傳給第二個命令,還是一邊處理一邊輸出呢?可能在大家是試驗中或者工作經驗中,應該是左邊的命令全部處理完再一次性交給右邊的命令進行處理,不光是大家,我在最初接觸管道時,也曾有這么一個誤會,因為我們通過現象看到的就是這樣。

          關于Linux的匿名管道你了解多少?

          但其實只要有簡單了解過管道這工具,應該都不難得出解釋:

          管道是兩邊是同時進行,也就是說,左邊的命令輸出到管道,管道的右邊將馬上進行處理.

          一、管道的定義

          管道是由內核管理的一個緩沖區,相當于我們放入內存中的一個紙條。管道的一端連接一個進程的輸出。這個進程會向管道中放入信息。管道的另一端連接一個進程的輸入,這個進程取出被放入管道的信息。一個緩沖區不需要很大,它被設計成為環形的數據結構,以便管道可以被循環利用。當管道中沒有信息的話,從管道中讀取的進程會等待,直到另一端的進程放入信息。當管道被放滿信息的時候,嘗試放入信息的進程會堵塞,直到另一端的進程取出信息。當兩個進程都終結的時候,管道也自動消失。

          二、管道工作流程圖

          關于Linux的匿名管道你了解多少?

          通過上面的解釋可以看到,假設COMMAND1 | COMMAND2,那么COMMAND1的標準輸出,將會被綁定到管道的寫端,而COMMAND2的標準輸入將會綁定到管道的讀端, 所以當COMMAND1一有輸出,將會馬上通過管道傳給COMMAND2,我們先來做個實驗驗證下:

          # 1.py
          
          import time
          
          import sys
          
          while 1:
          
          print '1111'
          
          time.sleep(3)
          
          print '2222'
          
          time.sleep(3)
          
          [root@iZ23pynfq19Z ~]# python 1 | 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字節, 你們也可以試下這個值, 估計都一樣

          import time
          
          import sys
          
          while 1:
          
          print '1111' * 4096
          
          time.sleep(3)
          
          print '2222' * 4096
          
          time.sleep(3)
          
          # 方式2: 手動刷入寫隊列
          
          import time
          
          import sys
          
          while 1:
          
          print '1111'
          
          sys.stdout.flush() // 因為是標準輸出, 所以直接通過sys的接口去flush
          
          time.sleep(3)
          
          print '2222'
          
          sys.stdout.flush()
          
          time.sleep(3)

          輸出結果:

          # 第一種方式:

          [root@iZ23pynfq19Z ~]# python 1 | cat

          1111.....(超多1, 刷屏了..)

          睡眠3秒..

          2222.....(超多2, 刷屏了..)

          # 第二種方式:

          [root@iZ23pynfq19Z ~]# python 1 | cat

          1111

          睡眠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/python

          import time

          import sys

          while 1:

          time.sleep(10) # 手速不夠快的童鞋可以將睡眠時間設置長點

          print '1111'

          sys.stdout.flush()

          這次執行命令需要考驗手速了,因為我們要趕在py醒過來之前,將讀端進程殺掉

          python 1 | cat

          ------------------------

          # 另一個終端

          [root@iZ23pynfq19Z ~]# ps -fe | grep -P 'cat|python'

          root 10775 4074 0 00:05 pts/2 00:00:00 python 1

          root 10776 4074 0 00:05 pts/2 00:00:00 cat # 讀端進程

          root 10833 32581 0 00:06 pts/0 00:00:00 grep -P cat|python

          [root@iZ23pynfq19Z ~]# kill 10776

          輸出結果

          [root@iZ23pynfq19Z ~]# python 1 | cat

          Traceback (most recent call last):

          File "1", line 6, in <module>

          sys.stdout.flush()

          IOError: [Errno 32] Broken pipe

          Terminated

          從上圖我們可以驗證兩個點:

          · 當我們殺掉讀端時,寫端會收到SIGPIPE而默認退出,管道結束

          · 當我們殺掉讀端時,寫端的程序并不會馬上收到SIGPIPE,相反的,只有真正寫入管道寫端時才會觸發這個錯誤

          如果寫入一個 讀端已經關閉的管道,將會收到一個 SIGPIPE,那讀一個寫端已經關閉的管道又會這樣呢?

          import time

          import sys

          # 這次我們不需要死循環, 因為我們想要寫端快點關閉退出

          time.sleep(5)

          print '1111'

          sys.stdout.flush()

          # 因為我們想要 讀端 等到足夠長的時間, 讓寫端關閉, 所以我們需要利用awk先睡眠10秒

          [root@iZ23pynfq19Z ~]# python 1.py | awk '{system("sleep 10");print 123}'

          ------------------------

          [root@iZ23pynfq19Z ~]# ps -fe | grep -P 'awk|python'

          root 11717 4074 0 00:20 pts/2 00:00:00 python 1.py

          root 11718 4074 0 00:20 pts/2 00:00:00 awk {system("sleep 10");print 123}

          root 11721 32581 0 00:20 pts/0 00:00:00 grep -P awk|python

          # 5秒過后

          [root@iZ23pynfq19Z ~]# ps -fe | grep -P 'awk|python'

          root 11685 4074 0 00:20 pts/2 00:00:00 awk {system("sleep 10");print 123}

          root 11698 32581 0 00:20 pts/0 00:00:00 grep -P awk|python

          # 10秒過后

          [root@iZ23pynfq19Z ~]# python 1 | awk '{system("sleep 10");print 123}'

          123

          在上面也已經證明了上文提到的讀寫規則:如果所有管道寫端對應的文件描述符被關閉,將產生EOF結束標志,read返回0,程序退出。

          總結

          通過上面的理論和實驗,我們知道在使用管道時,兩邊命令的數據傳輸過程,以及對管道讀寫規則有了初步的認識,希望我們以后在工作時,再接觸管道時,能夠更加有把握的去利用這一強大的工具。

          以上就是本文為大家分享的關于Linux匿名管道的內容,希望對linux的小伙伴們有所幫助。

          預約申請免費試聽課

          怕錢不夠?就業掙錢后再付學費!    怕學不會?從入學起,達內定制課程!     擔心就業?達內多家實踐企業供你挑選!

          上一篇:測試工程師需要具備什么樣的素質
          下一篇:為什么說運維適合學習云計算

          初學者如何能學好編程?

          B端信息錄入:輸入框基礎設計細節解析(二)

          B端信息錄入:輸入框基礎設計細節解析(一)

          B端產品全局導航樣式與分析

          • 掃碼領取資料

            回復關鍵字:視頻資料

            免費領取 達內課程視頻學習資料

          • 視頻學習QQ群

            添加QQ群:1143617948

            免費領取達內課程視頻學習資料

          Copyright ? 2018 Tedu.cn All Rights Reserved 京ICP備08000853號-56 京公網安備 11010802029508號 達內時代科技集團有限公司 版權所有

          選擇城市和中心
          江西省

          貴州省

          廣西省

          海南省

          香蕉视频在线一级a做爰片免费观看视频 欧美成年性色生活片 百度 好搜 搜狗
          <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <文本链> <文本链> <文本链> <文本链> <文本链> <文本链>