python 多進(jìn)程 多線程 協(xié)程

一绅你、多進(jìn)程

1昭躺、子進(jìn)程(subprocess包)

在python中领炫,通過subprocess包,fork一個子進(jìn)程帝洪,并運行外部程序。

import subprocess
child1 = subprocess.Popen(["ls","-l"], stdout=subprocess.PIPE)
child2 = subprocess.Popen(["wc"], stdin=child1.stdout,stdout=subprocess.PIPE)
out = child2.communicate()
print(out)

subprocess參考
從subprocess運行的子進(jìn)程中實時獲取輸出

2啄枕、多進(jìn)程(multiprocessing包)

它可以利用multiprocessing.Process對象來創(chuàng)建一個進(jìn)程族沃。

進(jìn)程池 (Process Pool)可以創(chuàng)建多個進(jìn)程泌参。
apply_async(func,args) 從進(jìn)程池中取出一個進(jìn)程執(zhí)行func,args為func的參數(shù)盖溺。它將返回一個AsyncResult的對象铣缠,你可以對該對象調(diào)用get()方法以獲得結(jié)果。

close() 進(jìn)程池不再創(chuàng)建新的進(jìn)程

join()方法可以等待子進(jìn)程結(jié)束后再繼續(xù)往下運行蝇庭,通常用于進(jìn)程間的同步捡硅。

join() wait進(jìn)程池中的全部進(jìn)程。必須對Pool先調(diào)用close()方法才能join北发。

#! /usr/bin/env python
# -*- coding:utf-8   -*-
# __author__ == "111"
# "我的電腦有4個cpu"

from multiprocessing import Pool
import os, time

def long_time_task(name):
    print 'Run task %s (%s)...' % (name, os.getpid())
    start = time.time()
    time.sleep(3)
    end = time.time()
    print 'Task %s runs %0.2f seconds.' % (name, (end - start))

if __name__=='__main__':
    print 'Parent process %s.' % os.getpid()
    p = Pool()
    for i in range(4):
        p.apply_async(long_time_task, args=(i,))
    print 'Waiting for all subprocesses done...'
    p.close()
    p.join()
    print 'All subprocesses done.'
多進(jìn)程共享資源

通過共享內(nèi)存和Manager對象:用一個進(jìn)程作為服務(wù)器喷屋,建立Manager來真正存放資源。
其它的進(jìn)程可以通過參數(shù)傳遞或者根據(jù)地址來訪問Manager狱庇,建立連接后,操作服務(wù)器上的資源陕截。

#! /usr/bin/env python
# -*- coding:utf-8   -*-
# __author__ == "111"

from multiprocessing import Queue,Pool
import multiprocessing,time,random

def write(q):

    for value in  ['A','B','C','D']:
        print "Put %s to Queue!" % value
        q.put(value)
        time.sleep(random.random())


def read(q,lock):
    while True:
        lock.acquire()
        if not q.empty():
            value=q.get(True)
            print "Get %s from Queue" % value
            time.sleep(random.random())
        else:
            break
        lock.release()

if __name__ == "__main__":
    manager=multiprocessing.Manager()
    q=manager.Queue()
    p=Pool()
    lock=manager.Lock()
    pw=p.apply_async(write,args=(q,))
    pr=p.apply_async(read,args=(q,lock))
    p.close()
    p.join()
    print ("所有數(shù)據(jù)都寫入并且讀完")

二批什、多線程

threading包

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)

python的多線程在同一時刻只會有一條線程跑在CPU里面驻债,其他線程都在睡覺。這個就是因為傳說中的GIL(全局解釋鎖)的存在暮的。任何Python線程執(zhí)行前淌实,必須先獲得GIL鎖.

那python多線程還有用處嗎?當(dāng)然拆祈!

如果是一個計算為主的程序(專業(yè)一點稱為CPU密集型程序),這一點確實是比較吃虧的咙咽,每個線程運行一遍淤年,就相當(dāng)于單線程在跑,甚至比單線程還要慢——CPU切換線程的上下文也是要有開銷的溉苛。

辣雞

如果是一個磁盤或網(wǎng)絡(luò)為主的程序(IO密集型)就不同了豹休。一個線程處在IO等待的時候,另一個線程還可以在CPU里面跑凤巨,有時候CPU閑著沒事干洛搀,所有的線程都在等著IO,這時候他們就是同時的了留美,而單線程的話此時還是在一個一個等待的。我們都知道IO的速度比起CPU來是慢到令人發(fā)指的逢倍,python的多線程就在這時候發(fā)揮作用了。比方說多線程網(wǎng)絡(luò)傳輸碉哑,多線程往不同的目錄寫文件亮蒋,等等。

線程同步

多線程中贮尖,所有變量都由所有線程共享趁怔,所以,任何一個變量都可以被任何一個線程修改痕钢,因此任连,線程之間共享數(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
lock = threading.Lock()

def run_thread(n):
    for i in range(100000):
        # 先要獲取鎖:
        lock.acquire()
        try:
            # 放心地改吧:
            change_it(n)
        finally:
            # 改完了一定要釋放鎖:
            lock.release()

三全肮、協(xié)程

協(xié)程,又稱微線程辜腺,纖程乍恐。英文名Coroutine测砂。一句話說明什么是線程:協(xié)程是一種用戶態(tài)的輕量級線程。

線程是系統(tǒng)級別的砌些,它們是由操作系統(tǒng)調(diào)度;協(xié)程是程序級別的宙彪,由程序員根據(jù)需要自己調(diào)度有巧。我們把一個線程中的一個個函數(shù)叫做子程序,那么子程序在執(zhí)行過程中可以中斷去執(zhí)行別的子程序男图;別的子程序也可以中斷回來繼續(xù)執(zhí)行之前的子程序甜橱,這就是協(xié)程。也就是說同一線程下的一段代碼<1>執(zhí)行著執(zhí)行著就可以中斷难裆,然后跳去執(zhí)行另一段代碼镊掖,當(dāng)再次回來執(zhí)行代碼塊<1>的時候,接著從之前中斷的地方開始執(zhí)行症虑。

協(xié)程的優(yōu)點:

(1)無需線程上下文切換的開銷归薛,協(xié)程避免了無意義的調(diào)度,由此可以提高性能(但也因此主籍,程序員必須自己承擔(dān)調(diào)度的責(zé)任,同時沈条,協(xié)程也失去了標(biāo)準(zhǔn)線程使用多CPU的能力)

(2)無需原子操作鎖定及同步的開銷

(3)方便切換控制流诅炉,簡化編程模型

(4)高并發(fā)+高擴(kuò)展性+低成本:一個CPU支持上萬的協(xié)程都不是問題屋厘。所以很適合用于高并發(fā)處理汗洒。

協(xié)程的缺點:

(1)無法利用多核資源:協(xié)程的本質(zhì)是個單線程,它不能同時將 單個CPU 的多個核用上,協(xié)程需要和進(jìn)程配合才能運行在多CPU上.當(dāng)然我們?nèi)粘K帉懙慕^大部分應(yīng)用都沒有這個必要父款,除非是cpu密集型應(yīng)用。

(2)進(jìn)行阻塞(Blocking)操作(如IO時)會阻塞掉整個程序

參考:
https://www.cnblogs.com/zingp/p/5911537.html
https://blog.csdn.net/andybegin/article/details/77884645

四世杀、異步

無論是線程還是進(jìn)程肝集,使用的都是同步進(jìn)制,當(dāng)發(fā)生阻塞時所刀,性能會大幅度降低捞挥,無法充分利用CPU潛力,浪費硬件投資砌函,更重要造成軟件模塊的鐵板化胸嘴,緊耦合,無法切割劣像,不利于日后擴(kuò)展和變化摧玫。

不管是進(jìn)程還是線程诬像,每次阻塞、切換都需要陷入系統(tǒng)調(diào)用(system call)坏挠,先讓CPU跑操作系統(tǒng)的調(diào)度程序降狠,然后再由調(diào)度程序決定該跑哪一個進(jìn)程(線程)庇楞。多個線程之間在一些訪問互斥的代碼時還需要加上鎖否纬,

現(xiàn)下流行的異步server都是基于事件驅(qū)動的(如nginx)。

異步事件驅(qū)動模型中睛驳,把會導(dǎo)致阻塞的操作轉(zhuǎn)化為一個異步操作膜廊,主線程負(fù)責(zé)發(fā)起這個異步操作,并處理這個異步操作的結(jié)果蹬跃。由于所有阻塞的操作都轉(zhuǎn)化為異步操作钥勋,理論上主線程的大部分時間都是在處理實際的計算任務(wù),少了多線程的調(diào)度時間算灸,所以這種模型的性能通常會比較好菲驴。

參考:https://www.cnblogs.com/tyomcat/p/5486827.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市先煎,隨后出現(xiàn)的幾起案子巧涧,更是在濱河造成了極大的恐慌,老刑警劉巖占锯,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件消略,死亡現(xiàn)場離奇詭異瞎抛,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門胎撤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來晓殊,“玉大人,你說我怎么就攤上這事哩照⊥ξ铮” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵飘弧,是天一觀的道長识藤。 經(jīng)常有香客問我,道長次伶,這世上最難降的妖魔是什么痴昧? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮赶撰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘柱彻。我一直安慰自己豪娜,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布哟楷。 她就那樣靜靜地躺著瘤载,像睡著了一般。 火紅的嫁衣襯著肌膚如雪卖擅。 梳的紋絲不亂的頭發(fā)上鸣奔,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機(jī)與錄音惩阶,去河邊找鬼挎狸。 笑死,一個胖子當(dāng)著我的面吹牛断楷,可吹牛的內(nèi)容都是我干的锨匆。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼冬筒,長吁一口氣:“原來是場噩夢啊……” “哼统刮!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起账千,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎暗膜,沒想到半個月后匀奏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡学搜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年娃善,在試婚紗的時候發(fā)現(xiàn)自己被綠了论衍。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡聚磺,死狀恐怖坯台,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瘫寝,我是刑警寧澤蜒蕾,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站焕阿,受9級特大地震影響咪啡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜暮屡,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一撤摸、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧褒纲,春花似錦准夷、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至汁蝶,卻和暖如春渐扮,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背掖棉。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工墓律, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人幔亥。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓耻讽,卻偏偏與公主長得像,于是被迫代替她去往敵國和親帕棉。 傳聞我的和親對象是個殘疾皇子针肥,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

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