欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

為什么Python自帶的Print函數(shù)會報錯

本篇內(nèi)容主要講解“為什么Python自帶的Print函數(shù)會報錯”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“為什么Python自帶的Print函數(shù)會報錯”吧!

創(chuàng)新互聯(lián)網(wǎng)站建設(shè)由有經(jīng)驗(yàn)的網(wǎng)站設(shè)計師、開發(fā)人員和項(xiàng)目經(jīng)理組成的專業(yè)建站團(tuán)隊(duì),負(fù)責(zé)網(wǎng)站視覺設(shè)計、用戶體驗(yàn)優(yōu)化、交互設(shè)計和前端開發(fā)等方面的工作,以確保網(wǎng)站外觀精美、成都網(wǎng)站設(shè)計、成都做網(wǎng)站易于使用并且具有良好的響應(yīng)性。

前言

最近用 Python 寫了幾個簡單的腳本來處理一些數(shù)據(jù),因?yàn)橹皇呛唵喂δ芩晕揖椭苯邮褂?print 來打印日志。

任務(wù)運(yùn)行時偶爾會出現(xiàn)一些異常:

為什么Python自帶的Print函數(shù)會報錯

因?yàn)槲以诓煌胤蕉加写蛴∪罩?,?dǎo)致每次報錯的地方都不太一樣,從而導(dǎo)致程序運(yùn)行結(jié)果非常詭異;有時候是這段代碼沒有運(yùn)行,下一次就可能是另外一段代碼沒有觸發(fā)。

雖說當(dāng)時有注意到 Broken pipe 這個關(guān)鍵異常,但沒有特別在意,因?yàn)榇a中也有一些發(fā)送 http 請求的地方,一直以為是網(wǎng)絡(luò) IO  出現(xiàn)了問題,壓根沒往 print 這個最基本的打印函數(shù)上思考??。

直到這個問題反復(fù)出現(xiàn)我才認(rèn)真看了這個異常,定睛一看 print 不也是 IO 操作嘛,難道真的是自帶的 print 函數(shù)都出問題了?

但在本地、測試環(huán)境我運(yùn)行無數(shù)次也沒能發(fā)現(xiàn)異常;于是我找運(yùn)維拿到了線上的運(yùn)行方式。

原來為了方便維護(hù)大家提交上來的腳本任務(wù),運(yùn)維自己有維護(hù)一個統(tǒng)一的腳本,在這個腳本中使用:

cmd = 'python /xxx/test.py' os.popen(cmd)

來觸發(fā)任務(wù),這也是與我在本地、開發(fā)環(huán)境的唯一區(qū)別。

popen 原理

為此我在開發(fā)環(huán)境模擬出了異常:

test.py:

import time if __name__ == '__main__':     time.sleep(20)     print '1000'*1024

task.py:

import os import time if __name__ == '__main__':     start = int(time.time())     cmd = 'python test.py'     os.popen(cmd)     end = int(time.time())     print 'end****{}s'.format(end-start)

運(yùn)行:

python task.py

等待 20s 必然會復(fù)現(xiàn)這個異常:

Traceback (most recent call last):   File "test.py", line 4, in <module>     print '1000'*1024 IOError: [Errno 32] Broken pipe

為什么會出現(xiàn)這個異常呢?

首先得了解 os.popen(command[, mode[, bufsize]]) 這個函數(shù)的運(yùn)行原理。

為什么Python自帶的Print函數(shù)會報錯

根據(jù)官方文檔的解釋,該函數(shù)會執(zhí)行 fork 一個子進(jìn)程執(zhí)行 command 這個命令,同時將子進(jìn)程的標(biāo)準(zhǔn)輸出通過管道連接到父進(jìn)程;

也就該方法返回的文件描述符。

這里畫個圖能更好地理解其中的原理:

為什么Python自帶的Print函數(shù)會報錯

在這里的使用場景中并沒有獲取 popen() 的返回值,所以 command 的執(zhí)行本質(zhì)上是異步的;

也就是說當(dāng) task.py 執(zhí)行完畢后會自動關(guān)閉讀取端的管道。

為什么Python自帶的Print函數(shù)會報錯

如圖所示,關(guān)閉之后子進(jìn)程會向 pipe 中輸出 print  '1000'*1024,由于這里輸出的內(nèi)容較多會一下子填滿管道的緩沖區(qū);

于是寫入端會收到 SIGPIPE 信號,從而導(dǎo)致 Broken pipe 的異常。

從維基百科中我們也可以看出這個異常產(chǎn)生的一些條件:

為什么Python自帶的Print函數(shù)會報錯

其中也提到了 SIGPIPE 信號。

解決辦法

既然知道了問題原因,那解決起來就比較簡單了,主要有以下幾個方案:

使用 read() 函數(shù)讀取管道中的數(shù)據(jù),全部讀取之后再關(guān)閉。

如果不需要子進(jìn)程中的輸出時,也可以將 command 的標(biāo)準(zhǔn)輸出重定向到 /dev/null。

也可以使用 Python3 的 subprocess.Popen 模塊來運(yùn)行。

這里使用第一種方案進(jìn)行演示:

import os import time if __name__ == '__main__':     start = int(time.time())     cmd = 'python test.py'     with os.popen(cmd) as p:         print p.read()     end = int(time.time())     print 'end****{}s'.format(end-start)

為什么Python自帶的Print函數(shù)會報錯

運(yùn)行 task.py 之后不會再拋異常,同時也將 command 的輸出打印出來。

線上修復(fù)時我沒有采用這個方案,為了方便查看日志,還是使用標(biāo)準(zhǔn)的日志框架將日志輸出到了 es 中,方便統(tǒng)一在 kibana 中進(jìn)行查看。

由于日志框架并沒有使用到管道,所以自然也不會有這個問題。

更多內(nèi)容

問題雖然是解決了,其中還是涉及到了一些咱們平時不太注意的知識點(diǎn),這次我們就來一起回顧一下。

首先是父子進(jìn)程的內(nèi)容,這個在 c/c++/python 中比較常見,在 Java/golang 中直接使用多線程、協(xié)程會更多一些。

比如這次提到的 Python 中的 os.popen() 就是創(chuàng)建了一個子進(jìn)程,既然是子進(jìn)程那肯定是需要和父進(jìn)程進(jìn)行通信才能達(dá)到協(xié)同工作的目的。

很容易想到,父子進(jìn)程之間可以通過上文提到的管道(匿名管道)來進(jìn)行通信。

還是以剛才的 Python 程序?yàn)槔?dāng)運(yùn)行 task.py 后會生成兩個進(jìn)程:

為什么Python自帶的Print函數(shù)會報錯

分別進(jìn)入這兩個程序的/proc/pid/fd 目錄可以看到這兩個進(jìn)程所打開的文件描述符。

父進(jìn)程:

為什么Python自帶的Print函數(shù)會報錯

子進(jìn)程:

為什么Python自帶的Print函數(shù)會報錯

可以看到子進(jìn)程的標(biāo)準(zhǔn)輸出與父進(jìn)程關(guān)聯(lián),也就是 popen() 所返回的那個文件描述符。

這里的 0 1 2 分別對應(yīng)一個進(jìn)程的stdin(標(biāo)準(zhǔn)輸入)/stdout(標(biāo)準(zhǔn)輸出)/stderr(標(biāo)準(zhǔn)錯誤)。

還有一點(diǎn)需要注意的是,當(dāng)我們在父進(jìn)程中打開的文件描述符,子進(jìn)程也會繼承過去;

比如在 task.py 中新增一段代碼:

x = open("1.txt", "w")

之后查看文件描述符時會發(fā)現(xiàn)父子進(jìn)程都會有這個文件:

為什么Python自帶的Print函數(shù)會報錯

但相反的,子進(jìn)程中打開的文件父進(jìn)程是不會有的,這個應(yīng)該很容易理解。

總結(jié)

一些基礎(chǔ)知識在排查一些詭異問題時顯得尤為重要,比如本次涉及到的父子進(jìn)程的管道通信,最后來總結(jié)一下:

os.popen() 函數(shù)是異步執(zhí)行的,如果需要拿到子進(jìn)程的輸出,需要自行調(diào)用 read() 函數(shù)。

父子進(jìn)程是通過匿名管道進(jìn)行通信的,當(dāng)讀取端關(guān)閉時,寫入端輸出到達(dá)管道最大緩存時會收到 SIGPIPE 信號,從而拋出 Broken pipe  異常。

子進(jìn)程會繼承父進(jìn)程的文件描述符。

到此,相信大家對“為什么Python自帶的Print函數(shù)會報錯”有了更深的了解,不妨來實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

本文題目:為什么Python自帶的Print函數(shù)會報錯
文章網(wǎng)址:http://chinadenli.net/article2/jeeeic.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站排名、關(guān)鍵詞優(yōu)化網(wǎng)站內(nèi)鏈網(wǎng)站改版、靜態(tài)網(wǎng)站搜索引擎優(yōu)化

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

綿陽服務(wù)器托管
国产精品亚洲综合天堂夜夜| 欧美日韩一区二区午夜| 亚洲欧洲精品一区二区三区| 国产大屁股喷水在线观看视频 | 亚洲精品av少妇在线观看| 日本丰满大奶熟女一区二区| 国产亚洲中文日韩欧美综合网| 国产专区亚洲专区久久| 男人把女人操得嗷嗷叫| 亚洲欧美日韩色图七区| 亚洲视频在线观看你懂的| 日韩专区欧美中文字幕| 亚洲精品熟女国产多毛| 国产欧美一区二区久久| 国产成人亚洲欧美二区综| 国语久精品在视频在线观看| 少妇人妻精品一区二区三区| 色小姐干香蕉在线综合网| 九九热这里有精品20| 国产精品白丝久久av| 高清国产日韩欧美熟女| 年轻女房东2中文字幕| 亚洲妇女作爱一区二区三区| 日韩人妻中文字幕精品| 一区二区不卡免费观看免费| 日韩精品成区中文字幕| 丰满少妇被粗大猛烈进出视频| 国产三级黄片在线免费看| 丰满少妇被猛烈插入在线观看| 亚洲av成人一区二区三区在线| 激情图日韩精品中文字幕| 久热香蕉精品视频在线播放| 亚洲av熟女国产一区二区三区站| 色综合久久六月婷婷中文字幕| 又大又长又粗又猛国产精品| 视频一区二区 国产精品| 国内九一激情白浆发布| 国产男女激情在线视频| 国产又粗又猛又爽色噜噜| 日韩高清一区二区三区四区| 日本不卡在线一区二区三区|