線程:簡單來說,一個進程中包含多個線程,比如打開一個 QQ(進程),然后你一邊聊 QQ(一個線程),一邊用 QQ 傳送文件(一個線程),等等。在一個進程內部,要同時干多件事,就需要同時運行多個“子任務”,我們把進程內的這些“子任務”稱為線程( Thread )。
進程是CPU資源分配的基本單位,
線程是獨立運行和獨立調度的基本單位(CPU上真正運行的是線程)。
進程擁有自己的資源空間,一個進程包含若干個線程,線程與CPU資源分配無關,多個線程共享同一進程內的資源。
在大多數編程語言中因為切換消耗的資源更少,多線程比多進程效率更高
對于python:
對CPU密集型代碼(比如循環計算,海量運算,機器學習等) : 多進程效率更高
對IO密集型代碼(比如文件操作,網絡爬蟲): 多線程效率更高。
進程multiprocessing
import multiprocessing
import os
from multiprocessing import cpu_count
from multiprocessing import Pool
import time
if __name__ == '__main__':N = int(input())# 多進程CPU_COUNT =cpu_count() ##CPU內核數 本機為8pool = Pool(CPU_COUNT)#進程池創建result = []for i in range(CPU_COUNT):result.append(pool.apply_async(howMany, (sepList[i], )))#創建進程
#Pool對象調用join方法,會等待所有的子進程執行完畢;
#調用join方法之前,必須調用close;
#調用close之后,就不能繼續添加新的Process了。pool.close()#pool.join()ans = 0list = [res.get() for res in result]print(sum(list), end = '')
鎖案例
import multiprocessing
def func(lock, data):lock.acquire()try:# 在這里對共享數據進行操作data.value += 1finally:lock.release()if __name__ == '__main__':lock = multiprocessing.Lock()data = multiprocessing.Value('i', 0)p1 = multiprocessing.Process(target=func, args=(lock, data))p2 = multiprocessing.Process(target=func, args=(lock, data))p1.start()p2.start()p1.join()p2.join()print(data.value)
鎖:l.acquire()
釋放 l.release()
pool.close() 關閉進程池,無法通過該進程池再創建新進程
pool.join() 主進程阻塞等待子進程的退出
線程:threading
if __name__ == '__main__':N = int(input())threadNum = 32t = []sepList = seprateNum(N, threadNum)for i in range(0, threadNum):t.append(threading.Thread(target = howMany, args = (sepList[i], )))t[i].start()for i in range(0, threadNum):t[i].join()print(N - 1 - ans, end = '')
lock = threading.Lock()
lock.acquire()#互斥鎖 保證一個線程在運行時不會讀到這個global_num += 1lock.release()
為了更好解決這個問題,Python 線程庫實現了 ThreadLocal 變量(很多語言都有類似的實現,比如 Java)。ThreadLocal 真正做到了線程之間的數據隔離,并且使用時,不需要手動獲取自己的線程 ID,如下示例:
import threading
global_data = threading.local()def show():print (threading.current_thread().getName(), global_data.num)
def thread_cal():global_data.num = str(threading.current_thread().getName()).split("-")[1]show()thread = []
for i in range(10):thread.append(threading.Thread(target = thread_cal))thread[i].start()
for i in range(10):thread[i].join()print ("Main thread: ", global_data.__dict__ )
輸出為每個線程名稱
上面示例中,每個線程都可以通過 global_data.num, 獲得自己獨有的數據,并且每個線程讀取到的 global_data 都不同,真正做到線程之間的隔離。c0ab1072ab50e3eaaa6a0f3726c6bb7e.png