1105| subprocess,多線程

http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143192823818768cd506abbc94eb5916192364506fa5d000

subprocess的目的就是啟動一個新的進程并且與之通信.

subprocess模塊中只定義了一個類: Popen卦方∪怕ィ可以使用Popen來創(chuàng)建進程蓬坡,并與進程進行復雜的交互燃少。它的構(gòu)造函數(shù)如下:

subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0)

參數(shù)args可以是字符串或者序列類型(如:list太惠,元組)氛琢,用于指定進程的可執(zhí)行文件及其參數(shù)黄虱。如果是序列類型袭艺,第一個元素通常是可執(zhí)行文件的路徑。我們也可以顯式的使用executeable參數(shù)來指定可執(zhí)行文件的路徑佑稠。

參數(shù)stdin, stdout, stderr分別表示程序的標準輸入秒梅、輸出、錯誤句柄舌胶。他們可以是PIPE捆蜀,文件描述符或文件對象,也可以設(shè)置為None,表示從父進程繼承辆它。

如果參數(shù)shell設(shè)為true誊薄,程序?qū)⑼ㄟ^shell來執(zhí)行。

參數(shù)env是字典類型娩井,用于指定子進程的環(huán)境變量暇屋。如果env = None,子進程的環(huán)境變量將從父進程中繼承洞辣。

subprocess.PIPE

在創(chuàng)建Popen對象時咐刨,subprocess.PIPE可以初始化stdin, stdout或stderr參數(shù)。表示與子進程通信的標準流扬霜。

subprocess.STDOUT

創(chuàng)建Popen對象時定鸟,用于初始化stderr參數(shù),表示將錯誤通過標準輸出流輸出著瓶。

Popen的方法:

Popen.poll()

用于檢查子進程是否已經(jīng)結(jié)束联予。設(shè)置并返回returncode屬性。

Popen.wait()

等待子進程結(jié)束材原。設(shè)置并返回returncode屬性沸久。

Popen.communicate(input=None)

與子進程進行交互。向stdin發(fā)送數(shù)據(jù)余蟹,或從stdout和stderr中讀取數(shù)據(jù)卷胯。可選參數(shù)input指定發(fā)送到子進程的參數(shù)威酒。Communicate()返回一個元組:(stdoutdata, stderrdata)窑睁。注意:如果希望通過進程的stdin向其發(fā)送數(shù)據(jù),在創(chuàng)建Popen對象的時候葵孤,參數(shù)stdin必須被設(shè)置為PIPE担钮。同樣,如果希望從stdout和stderr獲取數(shù)據(jù)尤仍,必須將stdout和stderr設(shè)置為PIPE箫津。

Popen.send_signal(signal)

向子進程發(fā)送信號。

Popen.terminate()

停止(stop)子進程宰啦。在windows平臺下鲤嫡,該方法將調(diào)用Windows API TerminateProcess()來結(jié)束子進程。

Popen.kill()

殺死子進程绑莺。

Popen.stdin,Popen.stdout 惕耕,Popen.stderr 纺裁,官方文檔上這么說:

stdin, stdout and stderr specify the executed programs’ standard input, standard output and standard error file handles, respectively. Valid values are PIPE, an existing file descriptor (a positive integer), an existing file object, and None.

Popen.pid

獲取子進程的進程ID。

Popen.returncode

獲取進程的返回值。如果進程還沒有結(jié)束欺缘,返回None栋豫。


多線程

閱讀: 8588
多任務(wù)可以由多進程完成,也可以由一個進程內(nèi)的多線程完成谚殊。

我們前面提到了進程是由若干線程組成的丧鸯,一個進程至少有一個線程。

由于線程是操作系統(tǒng)直接支持的執(zhí)行單元嫩絮,因此丛肢,高級語言通常都內(nèi)置多線程的支持,Python也不例外剿干,并且蜂怎,Python的線程是真正的Posix Thread,而不是模擬出來的線程置尔。

Python的標準庫提供了兩個模塊:_thread和threading杠步,_thread是低級模塊,threading是高級模塊榜轿,對_thread進行了封裝幽歼。絕大多數(shù)情況下,我們只需要使用threading這個高級模塊谬盐。

啟動一個線程就是把一個函數(shù)傳入并創(chuàng)建Thread實例甸私,然后調(diào)用start()開始執(zhí)行:

import time, threading

新線程執(zhí)行的代碼:

def loop():
print('thread %s is running...' % threading.current_thread().name)
n = 0
while n < 5:
n = n + 1
print('thread %s >>> %s' % (threading.current_thread().name, n))
time.sleep(1)
print('thread %s ended.' % threading.current_thread().name)

print('thread %s is running...' % threading.current_thread().name)
t = threading.Thread(target=loop, name='LoopThread')
t.start()
t.join()
print('thread %s ended.' % threading.current_thread().name)
執(zhí)行結(jié)果如下:

thread MainThread is running...
thread LoopThread is running...
thread LoopThread >>> 1
thread LoopThread >>> 2
thread LoopThread >>> 3
thread LoopThread >>> 4
thread LoopThread >>> 5
thread LoopThread ended.
thread MainThread ended.
由于任何進程默認就會啟動一個線程,我們把該線程稱為主線程设褐,主線程又可以啟動新的線程颠蕴,Python的threading模塊有個current_thread()函數(shù),它永遠返回當前線程的實例助析。主線程實例的名字叫MainThread犀被,子線程的名字在創(chuàng)建時指定,我們用LoopThread命名子線程外冀。名字僅僅在打印時用來顯示寡键,完全沒有其他意義,如果不起名字Python就自動給線程命名為Thread-1雪隧,Thread-2……

Lock

多線程和多進程最大的不同在于西轩,多進程中,同一個變量脑沿,各自有一份拷貝存在于每個進程中藕畔,互不影響,而多線程中庄拇,所有變量都由所有線程共享注服,所以韭邓,任何一個變量都可以被任何一個線程修改,因此溶弟,線程之間共享數(shù)據(jù)最大的危險在于多個線程同時改一個變量女淑,把內(nèi)容給改亂了。

import time, threading

假定這是你的銀行存款:

balance = 0

def change_it(n):
# 先存后取辜御,結(jié)果應(yīng)該為0:
global balance
balance = balance + n
balance = balance - n

def run_thread(n):
for i in range(100000):
change_it(n)

t1 = threading.Thread(target=run_thread, args=(5,))
t2 = threading.Thread(target=run_thread, args=(8,))
t1.start()
t2.start()
t1.join()
t2.join()
print(balance)
我們定義了一個共享變量balance鸭你,初始值為0,并且啟動兩個線程擒权,先存后取袱巨,理論上結(jié)果應(yīng)該為0,但是菜拓,由于線程的調(diào)度是由操作系統(tǒng)決定的瓣窄,當t1、t2交替執(zhí)行時纳鼎,只要循環(huán)次數(shù)足夠多俺夕,balance的結(jié)果就不一定是0了。

原因是因為高級語言的一條語句在CPU執(zhí)行時是若干條語句贱鄙,即使一個簡單的計算:

balance = balance + n
也分兩步:

計算balance + n劝贸,存入臨時變量中;
將臨時變量的值賦給balance逗宁。
也就是可以看成:

x = balance + n
balance = x
由于x是局部變量映九,兩個線程各自都有自己的x,當代碼正常執(zhí)行時:

初始值 balance = 0

t1: x1 = balance + 5 # x1 = 0 + 5 = 5
t1: balance = x1 # balance = 5
t1: x1 = balance - 5 # x1 = 5 - 5 = 0
t1: balance = x1 # balance = 0

t2: x2 = balance + 8 # x2 = 0 + 8 = 8
t2: balance = x2 # balance = 8
t2: x2 = balance - 8 # x2 = 8 - 8 = 0
t2: balance = x2 # balance = 0

結(jié)果 balance = 0
但是t1和t2是交替運行的瞎颗,如果操作系統(tǒng)以下面的順序執(zhí)行t1件甥、t2:

初始值 balance = 0

t1: x1 = balance + 5 # x1 = 0 + 5 = 5

t2: x2 = balance + 8 # x2 = 0 + 8 = 8
t2: balance = x2 # balance = 8

t1: balance = x1 # balance = 5
t1: x1 = balance - 5 # x1 = 5 - 5 = 0
t1: balance = x1 # balance = 0

t2: x2 = balance - 8 # x2 = 0 - 8 = -8
t2: balance = x2 # balance = -8

結(jié)果 balance = -8
究其原因,是因為修改balance需要多條語句哼拔,而執(zhí)行這幾條語句時引有,線程可能中斷,從而導致多個線程把同一個對象的內(nèi)容改亂了倦逐。

兩個線程同時一存一取譬正,就可能導致余額不對,你肯定不希望你的銀行存款莫名其妙地變成了負數(shù)檬姥,所以曾我,我們必須確保一個線程在修改balance的時候,別的線程一定不能改健民。

如果我們要確保balance計算正確抒巢,就要給change_it()上一把鎖,當某個線程開始執(zhí)行change_it()時秉犹,我們說虐秦,該線程因為獲得了鎖平酿,因此其他線程不能同時執(zhí)行change_it(),只能等待悦陋,直到鎖被釋放后,獲得該鎖以后才能改筑辨。由于鎖只有一個俺驶,無論多少線程,同一時刻最多只有一個線程持有該鎖棍辕,所以暮现,不會造成修改的沖突。創(chuàng)建一個鎖就是通過threading.Lock()來實現(xiàn):

balance = 0
lock = threading.Lock()

def run_thread(n):
for i in range(100000):
# 先要獲取鎖:
lock.acquire()
try:
# 放心地改吧:
change_it(n)
finally:
# 改完了一定要釋放鎖:
lock.release()
當多個線程同時執(zhí)行l(wèi)ock.acquire()時楚昭,只有一個線程能成功地獲取鎖栖袋,然后繼續(xù)執(zhí)行代碼,其他線程就繼續(xù)等待直到獲得鎖為止抚太。

獲得鎖的線程用完后一定要釋放鎖塘幅,否則那些苦苦等待鎖的線程將永遠等待下去,成為死線程尿贫。所以我們用try...finally來確保鎖一定會被釋放电媳。

鎖的好處就是確保了某段關(guān)鍵代碼只能由一個線程從頭到尾完整地執(zhí)行,壞處當然也很多庆亡,首先是阻止了多線程并發(fā)執(zhí)行匾乓,包含鎖的某段代碼實際上只能以單線程模式執(zhí)行,效率就大大地下降了又谋。其次拼缝,由于可以存在多個鎖,不同的線程持有不同的鎖彰亥,并試圖獲取對方持有的鎖時咧七,可能會造成死鎖,導致多個線程全部掛起剩愧,既不能執(zhí)行猪叙,也無法結(jié)束,只能靠操作系統(tǒng)強制終止仁卷。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末穴翩,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子锦积,更是在濱河造成了極大的恐慌芒帕,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丰介,死亡現(xiàn)場離奇詭異背蟆,居然都是意外死亡鉴分,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門带膀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來志珍,“玉大人,你說我怎么就攤上這事垛叨÷着矗” “怎么了?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵嗽元,是天一觀的道長敛纲。 經(jīng)常有香客問我,道長剂癌,這世上最難降的妖魔是什么淤翔? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮佩谷,結(jié)果婚禮上旁壮,老公的妹妹穿的比我還像新娘。我一直安慰自己琳要,他們只是感情好寡具,可當我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著稚补,像睡著了一般童叠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上课幕,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天厦坛,我揣著相機與錄音,去河邊找鬼乍惊。 笑死杜秸,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的润绎。 我是一名探鬼主播撬碟,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼莉撇!你這毒婦竟也來了呢蛤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤棍郎,失蹤者是張志新(化名)和其女友劉穎其障,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體涂佃,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡励翼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年蜈敢,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汽抚。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡抓狭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出殊橙,到底是詐尸還是另有隱情辐宾,我是刑警寧澤,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布膨蛮,位于F島的核電站,受9級特大地震影響季研,放射性物質(zhì)發(fā)生泄漏敞葛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一与涡、第九天 我趴在偏房一處隱蔽的房頂上張望惹谐。 院中可真熱鬧,春花似錦驼卖、人聲如沸氨肌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽怎囚。三九已至,卻和暖如春桥胞,著一層夾襖步出監(jiān)牢的瞬間恳守,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工贩虾, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留催烘,地道東北人。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓缎罢,卻偏偏與公主長得像伊群,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子策精,可洞房花燭夜當晚...
    茶點故事閱讀 44,689評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 處于學習別人代碼風格階段舰始,github參考學習程序程序開頭會有 一是用來指定腳本語言為 Python,二是用來指定...
    lifesmily閱讀 1,053評論 0 0
  • 我們前面提到了進程是由若干線程組成的蛮寂,一個進程至少有一個線程蔽午。多線程優(yōu)點: 在一個進程中的多線程和主線程分享相同的...
    第八共同體閱讀 520評論 0 0
  • 進程與線程的區(qū)別 現(xiàn)在,多核CPU已經(jīng)非常普及了酬蹋,但是及老,即使過去的單核CPU抽莱,也可以執(zhí)行多任務(wù)。由于CPU執(zhí)行代碼...
    蘇糊閱讀 767評論 0 2
  • 線程狀態(tài)新建骄恶,就緒食铐,運行,阻塞僧鲁,死亡虐呻。 線程同步多線程可以同時運行多個任務(wù),線程需要共享數(shù)據(jù)的時候寞秃,可能出現(xiàn)數(shù)據(jù)不...
    KevinCool閱讀 800評論 0 0
  • 1斟叼、聽《婷婷唱古詩》 2、讀 閱讀《手指謠》《嬰兒游戲繪本》睡覺啦春寿!《語言啟蒙》字詞擴展《小熊寶寶繪本》拉粑粑朗涩。對...
    馬行千里玥溢彩閱讀 144評論 0 0