摘要:對于操作為主的編程來說,多進程和多先產(chǎn)出的性能差別不大,甚至多線程比多進程的性能還高,因為多線程編程更加輕量級。
GIL
global interpreter lock(cpython)
同一時刻只有一個線程運行在一個cpu上執(zhí)行字節(jié)碼(無法將多個線程映射到多個cpu上)
import dis def add(a): a = a + 1 return a print(dis.dis(add))GIL在某些情況下會釋放
每次的結(jié)果都不一樣 線程之間的安全問題
GIL會根據(jù)執(zhí)行的直接碼行數(shù)或者時間片釋放GIL
遇到IO操作時主動釋放
total = 0 def add(): #1. dosomething1 #2. io操作 # 1. dosomething3 global total for i in range(1000000): total += 1 def desc(): global total for i in range(1000000): total -= 1 import threading thread1 = threading.Thread(target=add) thread2 = threading.Thread(target=desc) thread1.start() thread2.start() thread1.join() thread2.join() print(total)多線程編程
操作系統(tǒng)能夠調(diào)度的的最小單位是進程,因為進程對系統(tǒng)的資源消耗非常大,所以后期就演變成了線程,線程實際上是依賴于我們的進程(任務管理器中我們實際上能看到的其實是進程 ),操作系統(tǒng)能調(diào)度的最小單元是線程。
對于io操作為主的編程來說,多進程和多先產(chǎn)出的性能差別不大,甚至多線程比多進程的性能還高,因為多線程編程更加輕量級。
簡單的線程import time from threading import Thread def get_detail_html(url): print("get detail html started") time.sleep(2) print("get detail html end") def get_detail_url(url): print("get detail url started") time.sleep(4) print("get detail url end") if __name__ == "__main__": thread1 = Thread(target=get_detail_html, args=("",)) thread2 = Thread(target=get_detail_url, args=("",)) # 設(shè)置為守護線程 當主線程運行完時 子線程被kill掉 thread1.setDaemon(True) thread2.setDaemon(True) start_time = time.time() thread1.start() thread2.start() # 設(shè)置為阻塞 等待線程運行完再關(guān)閉主線程 thread1.join() thread2.join() # 默認情況下 主線程退出與時 子線程不會被kill掉 print("last time: {}".format(time.time() - start_time))重載線程實現(xiàn)多線程
import time import threading def get_detail_html(url): print("get detail html started") time.sleep(2) print("get detail html end") def get_detail_url(url): print("get detail url started") time.sleep(4) print("get detail url end") #2. 通過集成Thread來實現(xiàn)多線程 class GetDetailHtml(threading.Thread): def __init__(self, name): super().__init__(name=name) def run(self): print("get detail html started") time.sleep(2) print("get detail html end") class GetDetailUrl(threading.Thread): def __init__(self, name): super().__init__(name=name) def run(self): print("get detail url started") time.sleep(4) print("get detail url end") if __name__ == "__main__": thread1 = GetDetailHtml("get_detail_html") thread2 = GetDetailUrl("get_detail_url") start_time = time.time() thread1.start() thread2.start() thread1.join() thread2.join() #當主線程退出的時候, 子線程kill掉 print ("last time: {}".format(time.time()-start_time))多線程之間的通信
使用queue
# filename: thread_queue_test.py # 通過queue的方式進行線程間同步 from queue import Queue import time import threading def get_detail_html(queue): # 死循環(huán) 爬取文章詳情頁 while True: url = queue.get() # for url in detail_url_list: print("get detail html started") time.sleep(2) print("get detail html end") def get_detail_url(queue): # 死循環(huán) 爬取文章列表頁 while True: print("get detail url started") time.sleep(4) for i in range(20): # put 等到有空閑位置 再放入 # put_nowait 非阻塞方式 queue.put("http://projectsedu.com/{id}".format(id=i)) print("get detail url end") # 1. 線程通信方式- 共享變量 if __name__ == "__main__": detail_url_queue = Queue(maxsize=1000) thread_detail_url = threading.Thread(target=get_detail_url, args=(detail_url_queue,)) for i in range(10): html_thread = threading.Thread(target=get_detail_html, args=(detail_url_queue,)) html_thread.start() start_time = time.time() # 調(diào)用task_down從主線程退出 detail_url_queue.task_done() # 從queue的角度阻塞 detail_url_queue.join() print("last time: {}".format(time.time() - start_time))線程的同步問題
在多線程編程中必須要面對的問題
無鎖不安全的原因# 沒有鎖 def add1(a): a += 1 def desc1(a): a -= 1 """add 1. load a a = 0 2. load 1 1 3. + 1 4. 賦值給a a=1 """ """add 1. load a a = 0 2. load 1 1 3. - 1 4. 賦值給a a=-1 """ import dis print(dis.dis(add1)) print(dis.dis(desc1))普通鎖(Lock)
用鎖會影響性能,鎖會引起死鎖(兩次獲取鎖,獲取鎖之后不釋放,互相等待(a需要b的資源 b需要a的資源))
import threading from threading import Lock total = 0 # 定義一把鎖 lock = Lock() def add(): global total global lock for i in range(1000000): # 獲取鎖 lock.acquire() total += 1 # 釋放鎖 lock.release() def desc(): global total for i in range(1000000): lock.acquire() total -= 1 lock.release() thread1 = threading.Thread(target=add) thread2 = threading.Thread(target=desc) thread1.start() thread2.start() thread1.join() thread2.join() print(total)相互等待(資源競爭)
""" A(a、b) acquire (a) acquire (b) B(a、b) acquire (b) acquire (a) # 解決辦法 B(a、b) acquire (a) acquire (b) """可重入鎖(Rlock)
import threading from threading import RLock total = 0 # 可重入鎖 可以在同一個線程中可載入多次 lock = RLock() def add(lock): global total for i in range(1000000): # 獲取鎖 lock.acquire() lock.acquire() total += 1 do_something(lock) # 釋放鎖 lock.release() lock.release() def desc(): global total for i in range(1000000): lock.acquire() total -= 1 lock.release() def do_something(lock): lock.acquire() # do something lock.release() thread1 = threading.Thread(target=add) thread2 = threading.Thread(target=desc) thread1.start() thread2.start() thread1.join() thread2.join() print(total)條件變量鎖(condition)
用于復雜的線程間同步
# 沒有條件鎖 不能實現(xiàn)對話 import threading class XiaoAi(threading.Thread): def __init__(self, lock): super().__init__(name="小愛") self.lock = lock def run(self): self.lock.acquire() print("{} : 在 ".format(self.name)) self.lock.release() self.lock.acquire() print("{} : 好啊 ".format(self.name)) self.lock.release() class TianMao(threading.Thread): def __init__(self, lock): super().__init__(name="天貓精靈") self.lock = lock def run(self): self.lock.acquire() print("{} : 小愛同學 ".format(self.name)) self.lock.release() self.lock.acquire() print("{} : 我們來對古詩吧 ".format(self.name)) self.lock.release() if __name__ == "__main__": cond = threading.Condition() xiaoai = XiaoAi(cond) tianmao = TianMao(cond) xiaoai.start() tianmao.start()
# 條件鎖 import threading class XiaoAi(threading.Thread): def __init__(self, cond): super().__init__(name="小愛") self.cond = cond def run(self): with self.cond: self.cond.wait() print("{} : 在 ".format(self.name)) self.cond.notify() self.cond.wait() print("{} : 好啊 ".format(self.name)) self.cond.notify() self.cond.wait() print("{} : 君住長江尾 ".format(self.name)) self.cond.notify() self.cond.wait() print("{} : 共飲長江水 ".format(self.name)) self.cond.notify() self.cond.wait() print("{} : 此恨何時已 ".format(self.name)) self.cond.notify() self.cond.wait() print("{} : 定不負相思意 ".format(self.name)) self.cond.notify() class TianMao(threading.Thread): def __init__(self, cond): super().__init__(name="天貓精靈") self.cond = cond def run(self): with self.cond: print("{} : 小愛同學 ".format(self.name)) self.cond.notify() self.cond.wait() print("{} : 我們來對古詩吧 ".format(self.name)) self.cond.notify() self.cond.wait() print("{} : 我住長江頭 ".format(self.name)) self.cond.notify() self.cond.wait() print("{} : 日日思君不見君 ".format(self.name)) self.cond.notify() self.cond.wait() print("{} : 此水幾時休 ".format(self.name)) self.cond.notify() self.cond.wait() print("{} : 只愿君心似我心 ".format(self.name)) self.cond.notify() self.cond.wait() if __name__ == "__main__": from concurrent import futures cond = threading.Condition() xiaoai = XiaoAi(cond) tianmao = TianMao(cond) # 啟動順序很重要 # 在調(diào)用with cond之后才能調(diào)用wait或者notify方法 # condition有兩層鎖, 一把底層鎖會在線程調(diào)用了wait方法的時候釋放, # 上面的鎖會在每次調(diào)用wait的時候分配一把并放入到cond的等待隊列中, # 等到notify方法的喚醒 xiaoai.start() tianmao.start()
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/42970.html
摘要:進程可創(chuàng)建多個線程來執(zhí)行同一程序的不同部分。就緒等待線程調(diào)度。運行線程正常運行阻塞暫停運行,解除阻塞后進入狀態(tài)重新等待調(diào)度。消亡線程方法執(zhí)行完畢返回或者異常終止。多線程多的情況下,依次執(zhí)行各線程的方法,前頭一個結(jié)束了才能執(zhí)行后面一個。 淺談Python多線程 作者簡介: 姓名:黃志成(小黃)博客: 博客 線程 一.什么是線程? 操作系統(tǒng)原理相關(guān)的書,基本都會提到一句很經(jīng)典的話: 進程...
摘要:多線程的理解多進程和多線程都可以執(zhí)行多個任務,線程是進程的一部分。多線程創(chuàng)建在中,同樣可以實現(xiàn)多線程,有兩個標準模塊和,不過我們主要使用更高級的模塊。多線程的應用場景。 1、多線程的理解 多進程和多線程都可以執(zhí)行多個任務,線程是進程的一部分。線程的特點是線程之間可以共享內(nèi)存和變量,資源消耗少(不過在Unix環(huán)境中,多進程和多線程資源調(diào)度消耗差距不明顯,Unix調(diào)度較快),缺點是線程之間...
摘要:其次,解釋器的主循環(huán),一個名為的函數(shù),讀取字節(jié)碼并逐個執(zhí)行其中的指令。所有線程都運行相同的代碼,并以相同的方式定期從它們獲取鎖定。無論如何,其他線程無法并行運行。 概述 如今我也是使用Python寫代碼好多年了,但是我卻很少關(guān)心GIL的內(nèi)部機制,導致在寫Python多線程程序的時候。今天我們就來看看CPython的源代碼,探索一下GIL的源碼,了解為什么Python里要存在這個GIL,...
摘要:上一篇文章進程專題完結(jié)篇多進程處理的一般建議下一篇文章線程專題多線程使用的必要性進程線程進程能夠完成多任務,比如在一個電腦上可以運行多個軟件。由于占用資源少,也使得多線程程序并發(fā)比較高。 上一篇文章:Python進程專題完結(jié)篇:多進程處理的一般建議下一篇文章:Python線程專題1:多線程使用的必要性 進程VS線程 進程:能夠完成多任務,比如在一個電腦上可以運行多個軟件。線程:也能夠...
摘要:也提供多線程支持,而且中的線程并非是模擬出來的多線程,而是系統(tǒng)級別的標準庫提供了兩個模塊和。同一個變量,線程則會互相共享。例如多個線程對銀行中的某一個賬戶進行操作。但是實際情況是隨意切換線程。說到的多線程編程,就會繞不過。 該文章參考了http://www.liaoxuefeng.com/wi... 廖雪峰的教程。 一個進程至少有一個線程。Python也提供多線程支持,而且Python...
摘要:多線程和鎖作者博客進程和線程進程是執(zhí)行中的計算機程序。線程包括開始執(zhí)行順序和結(jié)束三部分。的多進程相關(guān)模塊模塊是高級別的多線程模塊。線程鎖當多線程爭奪鎖時,允許第一個獲得鎖的線程進入臨街區(qū),并執(zhí)行代碼。 Python 多線程和鎖 作者博客:http://zzir.cn/ 進程和線程 進程是執(zhí)行中的計算機程序。每個進程都擁有自己的地址空間、內(nèi)存、數(shù)據(jù)棧及其它的輔助數(shù)據(jù)。操作系統(tǒng)管理著所有的...
閱讀 4211·2021-11-22 13:53
閱讀 3780·2021-11-19 11:29
閱讀 1650·2021-09-08 09:35
閱讀 3420·2020-12-03 17:26
閱讀 652·2019-08-29 16:06
閱讀 2291·2019-08-26 13:50
閱讀 1331·2019-08-23 18:32
閱讀 2324·2019-08-23 18:12