并行計算

Python有很多庫可以支持并行計算。

>>> import threading
>>> def thread_hello():
        other = threading.Thread(target=thread_say_hello, args=())
        other.start()
        thread_say_hello()
>>> def thread_say_hello():
        print('hello from', threading.current_thread().name)
>>> thread_hello()
hello from Thread-1
hello from MainThread

>>> import multiprocessing
>>> def process_hello():
        other = multiprocessing.Process(target=process_say_hello, args=())
        other.start()
        process_say_hello()
>>> def process_say_hello():
        print('hello from', multiprocessing.current_process().name)
>>> process_hello()
hello from MainProcess
hello from Process-1

threadingmultiprocessing庫有著類似的API呼巴,但是前者只是建立單個線程锥忿,后者對多進(jìn)程封裝得更完善,對多核CPU的支持更好羔挡。更多可閱讀Python標(biāo)準(zhǔn)庫08 多線程與同步 (threading包), Python標(biāo)準(zhǔn)庫10 多進(jìn)程初步 (multiprocessing包), Python多進(jìn)程并發(fā)(multiprocessing)

threading模塊使用線程,multiprocessing使用進(jìn)程间唉。其區(qū)別不同在于绞灼,線程使用同一內(nèi)存空間,而進(jìn)程分配有不同的內(nèi)存空間呈野。因此進(jìn)程間難以共享對象低矮。但兩個線程則有可能同時改寫同一內(nèi)存空間。為防止出現(xiàn)沖突被冒,可以使用GIL保證不會同時執(zhí)行可能沖突的線程军掂。
更多對比

下面是一個線程沖突的實例

import threading
from time import sleep

counter = [0]

def increment():
    count = counter[0]
    sleep(0) # try to force a switch to the other thread
    counter[0] = count + 1

other = threading.Thread(target=increment, args=())
other.start()
increment()
print('count is now: ', counter[0])

下面是執(zhí)行過程:

Thread 0                    Thread 1
read counter[0]: 0
                            read counter[0]: 0
calculate 0 + 1: 1
write 1 -> counter[0]
                            calculate 0 + 1: 1
                            write 1 -> counter[0]

問題在于:盡管執(zhí)行了兩次加法,但結(jié)果仍然是:1姆打。

在Python中,最簡單的保證數(shù)據(jù)同步的方法是使用queue模塊的Queue類肠虽。

from queue import Queue

queue = Queue()

def synchronized_consume():
    while True:
        print('got an item:', queue.get())  # 得到對象
        queue.task_done()                       # 隊列任務(wù)結(jié)束

def synchronized_produce():
    consumer = threading.Thread(target=synchronized_consume, args=())
    consumer.daemon = True
    consumer.start()
    for i in range(10):
        queue.put(i)           # 加入新對象
    queue.join()               # 確保所有隊列任務(wù)結(jié)束后幔戏,退出

synchronized_produce()

如果上面這個辦法因為某些原因做不到,那我們可以使用threading模塊中的Lock類税课。

seen = set()
seen_lock = threading.Lock()

def already_seen(item):
    seen_lock.acquire()       # 在Lock類的
    result = True             # acquire方法
    if item not in seen:      # 和release方法
        seen.add(item)        # 之間的代碼
        result = False        # 僅能同時被
    seen_lock.release()       # 一個線程訪問
    return result

def already_seen(item):
    with seen_lock:
        if item not in seen:
            seen.add(item)
            return False
        return True

還有一個辦法是threading模塊中的Barrier類闲延。

counters = [0, 0]
barrier = threading.Barrier(2)

def count(thread_num, steps):
    for i in range(steps):
        other = counters[1 - thread_num]
        barrier.wait() # wait for reads to complete
        counters[thread_num] = other + 1
        barrier.wait() # wait for writes to complete

def threaded_count(steps):
    other = threading.Thread(target=count, args=(1, steps))
    other.start()
    count(0, steps)
    print('counters:', counters)

threaded_count(10)

更多參考Python的多線程編程模塊 threading 參考痊剖,17.1. threading — Thread-based parallelism

防止共享數(shù)據(jù)錯誤讀寫的終極機(jī)制是完全避免并發(fā)地接觸同一數(shù)據(jù)垒玲。進(jìn)程的內(nèi)存空間的獨立性完全符合這一要求陆馁。為了解決進(jìn)程之間的交流問題,multiprocessing模塊特別提供了Pipe類合愈。Pipe默認(rèn)為兩條通道叮贩,如果傳入?yún)?shù)False則為一條通道。

def process_consume(in_pipe):
    while True:
        item = in_pipe.recv()  # 只有接收成功后才會繼續(xù)執(zhí)行
        if item is None:
            return
        print('got an item:', item)

def process_produce():
    pipe = multiprocessing.Pipe(False)
    consumer = multiprocessing.Process(target=process_consume, args=(pipe[0],))
    consumer.start()
    for i in range(10):
        pipe[1].send(i)        # 通過通道發(fā)送對象
    pipe[1].send(None) # done signal

process_produce()

在執(zhí)行并發(fā)計算時佛析,程序員往往會犯下錯誤:

  1. 同步不足(Under-synchronization):一些線程沒有被同步
  2. 過度同步(Over-synchronization):某些本可以并發(fā)執(zhí)行的線程益老,被串行化
  3. 死鎖(Deadlock):被同步的進(jìn)程相互等候?qū)Ψ酵瓿赡承┎襟E才進(jìn)行下一步,導(dǎo)致程序鎖死寸莫。一個栗子:
def deadlock(in_pipe, out_pipe):
    item = in_pipe.recv()
    print('got an item:', item)
    out_pipe.send(item + 1)

def create_deadlock():
    pipe = multiprocessing.Pipe()
    other = multiprocessing.Process(target=deadlock, args=(pipe[0], pipe[1]))
    other.start()
    deadlock(pipe[1], pipe[0])

create_deadlock()
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末捺萌,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子膘茎,更是在濱河造成了極大的恐慌桃纯,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件披坏,死亡現(xiàn)場離奇詭異态坦,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)刮萌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門驮配,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人着茸,你說我怎么就攤上這事壮锻。” “怎么了涮阔?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵猜绣,是天一觀的道長。 經(jīng)常有香客問我敬特,道長掰邢,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任伟阔,我火速辦了婚禮辣之,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘皱炉。我一直安慰自己怀估,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著多搀,像睡著了一般歧蕉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上康铭,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天惯退,我揣著相機(jī)與錄音,去河邊找鬼从藤。 笑死催跪,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的呛哟。 我是一名探鬼主播叠荠,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼扫责!你這毒婦竟也來了榛鼎?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤鳖孤,失蹤者是張志新(化名)和其女友劉穎者娱,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體苏揣,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡黄鳍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了平匈。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片框沟。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖增炭,靈堂內(nèi)的尸體忽然破棺而出忍燥,到底是詐尸還是另有隱情,我是刑警寧澤隙姿,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布梅垄,位于F島的核電站,受9級特大地震影響输玷,放射性物質(zhì)發(fā)生泄漏队丝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一欲鹏、第九天 我趴在偏房一處隱蔽的房頂上張望机久。 院中可真熱鬧,春花似錦赔嚎、人聲如沸膘盖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽衔憨。三九已至,卻和暖如春袄膏,著一層夾襖步出監(jiān)牢的瞬間践图,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工沉馆, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留码党,地道東北人。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓斥黑,卻偏偏與公主長得像揖盘,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子锌奴,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,612評論 2 350

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