国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > Python > 正文

Python多線(xiàn)程中阻塞(join)與鎖(Lock)使用誤區(qū)解析

2020-01-04 15:20:21
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

關(guān)于阻塞主線(xiàn)程

join的錯(cuò)誤用法

Thread.join() 作用為阻塞主線(xiàn)程,即在子線(xiàn)程未返回的時(shí)候,主線(xiàn)程等待其返回然后再繼續(xù)執(zhí)行.

join不能與start在循環(huán)里連用
以下為錯(cuò)誤代碼,代碼創(chuàng)建了5個(gè)線(xiàn)程,然后用一個(gè)循環(huán)激活線(xiàn)程,激活之后令其阻塞主線(xiàn)程.

threads = [Thread() for i in range(5)]for thread in threads: thread.start() thread.join()

執(zhí)行過(guò)程:

1. 第一次循環(huán)中,主線(xiàn)程通過(guò)start函數(shù)激活線(xiàn)程1,線(xiàn)程1進(jìn)行計(jì)算.
2. 由于start函數(shù)不阻塞主線(xiàn)程,在線(xiàn)程1進(jìn)行運(yùn)算的同時(shí),主線(xiàn)程向下執(zhí)行join函數(shù).
3. 執(zhí)行join之后,主線(xiàn)程被線(xiàn)程1阻塞,在線(xiàn)程1返回結(jié)果之前,主線(xiàn)程無(wú)法執(zhí)行下一輪循環(huán).
4. 線(xiàn)程1計(jì)算完成之后,解除對(duì)主線(xiàn)程的阻塞.
5. 主線(xiàn)程進(jìn)入下一輪循環(huán),激活線(xiàn)程2并被其阻塞…

如此往復(fù),可以看出,本來(lái)應(yīng)該并發(fā)的五個(gè)線(xiàn)程,在這里變成了順序隊(duì)列,效率和單線(xiàn)程無(wú)異.

join的正確用法

使用兩個(gè)循環(huán)分別處理startjoin函數(shù).即可實(shí)現(xiàn)并發(fā).

threads = [Thread() for i in range(5)]for thread in threads: thread.start()for thread in threads: thread.join()

time.sleep代替join進(jìn)行調(diào)試

之前在一些項(xiàng)目里看到過(guò)這樣的代碼,使用time.sleep代替join手動(dòng)阻塞主線(xiàn)程.
在所有子線(xiàn)程返回之前,主線(xiàn)程陷入無(wú)線(xiàn)循環(huán)而不能退出.

for thread in threads: thread.start()while 1: if thread_num == 0: break time.sleep(0.01)

關(guān)于線(xiàn)程鎖(threading.Lock)

單核CPU+PIL是否還需要鎖?

非原子操作 count = count + 1 理論上是線(xiàn)程不安全的.
使用3個(gè)線(xiàn)程同時(shí)執(zhí)行上述操作改變?nèi)肿兞縞ount的值,并查看程序執(zhí)行結(jié)果.
如果結(jié)果正確,則表示未出現(xiàn)線(xiàn)程沖突.

使用以下代碼測(cè)試

# -*- coding: utf-8 -*-import threadingimport timecount = 0class Counter(threading.Thread): def __init__(self, name): self.thread_name = name super(Counter, self).__init__(name=name) def run(self): global count for i in xrange(100000):  count = count + 1counters = [Counter('thread:%s' % i) for i in range(5)]for counter in counters: counter.start()time.sleep(5)print 'count=%s' % count

運(yùn)行結(jié)果:

count=275552

事實(shí)上每次運(yùn)行結(jié)果都不相同且不正確,這證明單核CPU+PIL仍無(wú)法保證線(xiàn)程安全,需要加鎖.

加鎖后的正確代碼:

# -*- coding: utf-8 -*-import threadingimport timecount = 0lock = threading.Lock()class Counter(threading.Thread): def __init__(self, name): self.thread_name = name self.lock = threading.Lock() super(Counter, self).__init__(name=name) def run(self): global count global lock for i in xrange(100000):  lock.acquire()  count = count + 1  lock.release()counters = [Counter('thread:%s' % i) for i in range(5)]for counter in counters: counter.start()time.sleep(5)print 'count=%s' % count

結(jié)果:

count=500000

注意鎖的全局性

這是一個(gè)簡(jiǎn)單的Python語(yǔ)法問(wèn)題,但在邏輯復(fù)雜時(shí)有可能被忽略.
要保證鎖對(duì)于多個(gè)子線(xiàn)程來(lái)說(shuō)是共用的,即不要在Thread的子類(lèi)內(nèi)部創(chuàng)建鎖.

以下為錯(cuò)誤代碼

# -*- coding: utf-8 -*-import threadingimport timecount = 0# lock = threading.Lock() # 正確的聲明位置class Counter(threading.Thread): def __init__(self, name): self.thread_name = name self.lock = threading.Lock() # 錯(cuò)誤的聲明位置 super(Counter, self).__init__(name=name) def run(self): global count for i in xrange(100000):  self.lock.acquire()  count = count + 1  self.lock.release()counters = [Counter('thread:%s' % i) for i in range(5)]for counter in counters: print counter.thread_name counter.start()time.sleep(5)print 'count=%s' % count

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持VEVB武林網(wǎng)。


注:相關(guān)教程知識(shí)閱讀請(qǐng)移步到python教程頻道。
發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 和静县| 丰都县| 边坝县| 利津县| 拉孜县| 偏关县| 永州市| 兴城市| 周宁县| 安陆市| 商水县| 孟津县| 旌德县| 仲巴县| 阿克陶县| 鄂伦春自治旗| 富裕县| 察哈| 遂昌县| 英吉沙县| 锦州市| 浦北县| 拜城县| 富锦市| 平原县| 治县。| 郴州市| 云梦县| 固阳县| 柳江县| 凤台县| 齐齐哈尔市| 玉环县| 镇沅| 镇平县| 黑龙江省| 义马市| 尤溪县| 民权县| 石景山区| 无锡市|