<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
眾所周知,CPU是計算機的核心,它承擔了所有的計算任務。而作業系統是計算機的管理者,是一個大管家,它負責任務的排程,資源的分配和管理,統領整個計算機硬體。應用程式是具有某種功能的程式,程式執行與作業系統之上
在很早的時候計算機並沒有執行緒這個概念,但是隨著時代的發展,只用程序來處理程式出現很多的不足。如當一個程序堵塞時,整個程式會停止在堵塞處,並且如果頻繁的切換程序,會浪費系統資源。所以執行緒出現了
執行緒是能擁有資源和獨立執行的最小單位,也是程式執行的最小單位。一個程序可以擁有多個執行緒,而且屬於同一個程序的多個執行緒間會共用該進行的資源
程序時一個具有一定功能的程式在一個資料集上的一次動態執行過程。程序由程式,資料集合和過程控制塊三部分組成。程式用於描述程序要完成的功能,是控制程序執行的指令集;資料集合是程式在執行時需要的資料和工作區;程式控制塊(PCB)包含程式的描述資訊和控制資訊,是程序存在的唯一標誌
一個程序由一個或者多個執行緒組成,執行緒是一個程序中程式碼的不同執行路線
切換程序需要的資源比切換執行緒的要多的多
程序之間相互獨立,而同一個程序下的執行緒共用程式的記憶體空間(如程式碼段,資料集,堆疊等)。某程序內的執行緒在其他程序不可見。換言之,執行緒共用同一片記憶體空間,而程序各有獨立的記憶體空間
在Python中,通過兩個標準庫 thread
和 Threading
提供對執行緒的支援, threading
對 thread
進行了封裝。 threading 模組中提供了 Thread , Lock , RLOCK , Condition 等元件
在Python中執行緒和程序的使用就是通過 Thread 這個類。這個類在我們的 thread 和 threading 模組中。我們一般通過 threading 匯入
預設情況下,只要在直譯器中,如果沒有報錯,則說明執行緒可用
from threading import Thread
引數 | 說明 |
---|---|
target | 表示呼叫物件,即子執行緒要執行的任務 |
name | 子執行緒的名稱 |
args | 傳入 target 函數中的位置引數,是一個元組,引數後必須新增逗號 |
import time, queue, threading class MyThread(threading.Thread): def __init__(self): super().__init__() self.daemon = True # 開啟守護模式 self.queue = queue.Queue(3) # 開啟佇列物件,儲存三個任務 self.start() # 範例化的時候直接啟動執行緒,不需要手動啟動執行緒 def run(self) -> None: # run方法執行緒自帶的方法,內建方法,線上程執行時會自動呼叫 while True: # 不斷處理任務 func, args, kwargs = self.queue.get() func(*args, **kwargs) # 呼叫函數執行任務 元組不定長記得一定要拆包 self.queue.task_done() # 解決一個任務就讓計數器減一,避免阻塞 # 生產者模型 def submit_tasks(self, func, args=(), kwargs={}): # func為要執行的任務,加入不定長引數使用(預設使用預設引數) self.queue.put((func, args, kwargs)) # 提交任務 # 重寫join方法 def join(self) -> None: self.queue.join() # 檢視佇列計時器是否為0 任務為空 為空關閉佇列 def f2(*args, **kwargs): time.sleep(2) print("任務2完成", args, kwargs) # 範例化執行緒物件 mt = MyThread() # 提交任務 mt.submit_tasks(f2, args=("aa", "aasd"), kwargs={"a": 2, "s": 3}) # 讓主執行緒等待子執行緒結束再結束 mt.join()
守護模式:
主執行緒在其他非守護執行緒執行完畢後才算執行完畢(守護執行緒在此時就被回收)。因為主執行緒的結束意味著程序的結束,程序整體的資源都將被回收,而程序必須保證非守護執行緒都執行完畢後才能結束
def f2(i): time.sleep(2) print("任務2完成", i) lis = [] for i in range(5): t = Thread(target=f2, args=(i,)) t.start() # 啟動 5 個執行緒 lis.append(t) for i in lis: i.join() # 執行緒等待
現在我們程式程式碼中,有多個執行緒, 並且在這個幾個執行緒中都會去 操作同一部分內容,那麼如何實現這些資料的共用呢?
這時,可以使用 threading
庫裡面的鎖物件 Lock 去保護
Lock 物件的acquire方法 是申請鎖
每個執行緒在操作共用資料物件之前,都應該申請獲取操作權,也就是呼叫該共用資料物件對應的鎖物件的acquire
方法,如果執行緒A 執行了acquire()
方法,別的執行緒B 已經申請到了這個鎖, 並且還沒有釋放,那麼 執行緒A的程式碼就在此處 等待 執行緒B 釋放鎖,不去執行後面的程式碼。
直到執行緒B 執行了鎖的 release
方法釋放了這個鎖, 執行緒A 才可以獲取這個鎖,就可以執行下面的程式碼了
如:
import threading var = 1 # 新增互斥鎖,並且拿到鎖 lock = threading.Lock() # 定義兩個執行緒要用做的任務 def func1(): global var # 宣告全域性變數 for i in range(1000000): lock.acquire() # 操作前上鎖 var += i lock.release() # 操作完後釋放鎖 def func2(): global var # 宣告全域性變數 for i in range(1000000): lock.acquire() # 操作前上鎖 var -= i lock.release() # 操作完後釋放鎖 # 建立2個執行緒 t1 = threading.Thread(target=func1) t2 = threading.Thread(target=func2) t1.start() t2.start() t1.join() t2.join() print(var)
到在使用多執行緒時,如果資料出現和自己預期不符的問題,就可以考慮是否是共用的資料被呼叫覆蓋的問題
使用 threading 庫裡面的鎖物件 Lock 去保護
Python中的多程序是通過multiprocessing
包來實現的,和多執行緒的threading.Thread
差不多,它可以利用multiprocessing.Process
物件來建立一個程序物件。這個程序物件的方法和執行緒物件的方法差不多也有start(), run(), join()等方法,其中有一個方法不同Thread執行緒物件中的守護執行緒方法是setDeamon,而Process程序物件的守護行程是通過設定daemon屬性來完成的
import time from multiprocessing import Process class MyProcess(Process): # 繼承Process類 def __init__(self, target, args=(), kwargs={}): super(MyProcess, self).__init__() self.daemon = True # 開啟守護行程 self.target = target self.args = args self.kwargs = kwargs self.start() # 自動開啟程序 def run(self): self.target(*self.args, **self.kwargs) def fun(*args, **kwargs): print(time.time()) print(args[0]) if __name__ == '__main__': lis = [] for i in range(5): p = MyProcess(fun, args=(1, )) lis.append(p) for i in lis: i.join() # 讓程序等待
守護模式:
主程序在其程式碼結束後就已經算執行完畢了(守護行程在此時就被回收),然後主程序會一直等非守護的子程序都執行完畢後回收子程序的資源(否則會產生殭屍程序),才會結束
import time from multiprocessing import Process def fun(*args, **kwargs): print(time.time()) print(args[0]) if __name__ == '__main__': lis = [] for i in range(5): p = Process(target=fun, args=(1, )) lis.append(p) for i in lis: i.join() # 讓程序等待
其使用方法和執行緒的那個 Lock 使用方法類似
Manager
的作用是提供多程序共用的全域性變數,Manager()
方法會返回一個物件,該物件控制著一個服務程序,該程序中儲存的物件執行其他程序使用代理進行操作
Manager支援的型別有:list,dict,Namespace,Lock,RLock,Semaphore,BoundedSemaphore,Condition,Event,Queue,Value和Array
語法:
from multiprocessing import Process, Lock, Manager def f(n, d, l, lock): lock.acquire() d[str(n)] = n l[n] = -99 lock.release() if __name__ == '__main__': lock = Lock() with Manager() as manager: d = manager.dict() # 空字典 l = manager.list(range(10)) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # 啟動10個程序,不同的程序對d和l中的不同元素進行操作 for i in range(10): p = Process(target=f, args=(i, d, l, lock)) p.start() p.join() print(d) print(l)
執行緒池的基礎類別是 concurrent.futures
模組中的 Executor , Executor 提供了兩個子類,即 ThreadPoolExecutor 和 ProcessPoolExecutor ,其中 ThreadPoolExecutor 用於建立執行緒池,而ProcessPoolExecutor
用於建立程序池
如果使用執行緒池/程序池來管理並行程式設計,那麼只要將相應的 task 函數提交給執行緒池/程序池,剩下的事情就由執行緒池/程序池來搞定
Exectuor 提供瞭如下常用方法:
程式將 task 函數提交(submit)給執行緒池後,submit 方法會返回一個 Future 物件,Future 類主要用於獲取執行緒任務函數的返回值。由於執行緒任務會在新執行緒中以非同步方式執行,因此,執行緒執行的函數相當於一個“將來完成”的任務,所以 Python 使用 Future 來代表
Future 提供瞭如下方法:
from multiprocessing import cpu_count # cpu核心數模組,其可以獲取 CPU 核心數 n = cpu_count() # 獲取cpu核心數
使用執行緒池來執行執行緒任務的步驟如下:
ThreadPoolExecutor
類的構造器建立一個執行緒池ThreadPoolExecutor
物件的 submit() 方法來提交執行緒任務ThreadPoolExecutor
物件的 shutdown() 方法來關閉執行緒池from concurrent.futures import ThreadPoolExecutor import threading import time # 定義一個準備作為執行緒任務的函數 def action(max): my_sum = 0 for i in range(max): print(threading.current_thread().name + ' ' + str(i)) my_sum += i return my_sum # 建立一個包含2條執行緒的執行緒池 pool = ThreadPoolExecutor(max_workers=2) # 向執行緒池提交一個task, 50會作為action()函數的引數 future1 = pool.submit(action, 50) # 向執行緒池再提交一個task, 100會作為action()函數的引數 future2 = pool.submit(action, 100) def get_result(future): print(future.result()) # 為future1新增執行緒完成的回撥函數 future1.add_done_callback(get_result) # 為future2新增執行緒完成的回撥函數 future2.add_done_callback(get_result) # 判斷future1代表的任務是否結束 print(future1.done()) time.sleep(3) # 判斷future2代表的任務是否結束 print(future2.done()) # 檢視future1代表的任務返回的結果 print(future1.result()) # 檢視future2代表的任務返回的結果 print(future2.result()) # 關閉執行緒池 pool.shutdown() # 序可以使用 with 語句來管理執行緒池,這樣即可避免手動關閉執行緒池
最佳執行緒數目 = ((執行緒等待時間+執行緒CPU時間)/執行緒CPU時間 )* CPU數目
也可以低於 CPU 核心數
使用執行緒池來執行執行緒任務的步驟如下:
ProcessPoolExecutor
類的構造器建立一個執行緒池ProcessPoolExecutor
物件的 submit() 方法來提交執行緒任務ProcessPoolExecutor
物件的 shutdown() 方法來關閉執行緒池關於程序的開啟程式碼一定要放在 if __name__ == '__main__': 程式碼之下,不能放到函數中或其他地方
開啟程序的技巧:
from concurrent.futures import ProcessPoolExecutor pool = ProcessPoolExecutor(max_workers=cpu_count()) # 根據cpu核心數開啟多少個程序
開啟程序的數量最好低於最大 CPU 核心數
到此這篇關於深入瞭解Python 中執行緒和程序區別的文章就介紹到這了,更多相關Python 中執行緒和程序內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45