第一時(shí)間獲取 Python 技術(shù)干貨,!眾所周知,,Python 中的多線程是一個(gè)假的多線程,,對(duì)于多核 CPU,由于受限于 GIL 全局解釋鎖,,同一時(shí)刻只能有一個(gè)線程在運(yùn)行,。但是對(duì)于經(jīng)常爬蟲(chóng)網(wǎng)絡(luò)請(qǐng)求、下載圖片等 IO 密集型操作,,多線程變的很實(shí)用,,能在一定程度上提高程序運(yùn)行的效率。下面帶大家從零開(kāi)始學(xué)習(xí) Python 多線程,。在單線程程序中可能包含多個(gè)方法,運(yùn)行程序后,,默認(rèn)是在一個(gè)主線程里按順序運(yùn)行,。import time
def exe_time(func): def new_func(*args, **args2): t0 = time.time() print("@%s, {%s} start" % (time.strftime("%X", time.localtime()), func.__name__)) back = func(*args, **args2) print("@%s, {%s} end" % (time.strftime("%X", time.localtime()), func.__name__)) print("@%.3fs taken for {%s}" % (time.time() - t0, func.__name__)) return back
return new_func
@exe_time def func1(): time.sleep(1) print('執(zhí)行方法1') time.sleep(2)
@exe_time def func2(): time.sleep(1) print('執(zhí)行方法2') time.sleep(2)
if __name__ == "__main__": func1() func2()
很明顯,如果方法內(nèi)部都是耗時(shí)的操作,,會(huì)顯得效率很低下,。涉及到網(wǎng)絡(luò),、磁盤(pán) IO 任務(wù)的都屬于IO 密集型,,比如:讀寫(xiě)文件、網(wǎng)絡(luò)請(qǐng)求等任務(wù),,計(jì)算量小,。CPU 密集型主要消耗 CPU 資源,比如:復(fù)雜的計(jì)算操作,、視頻高清解碼等,。對(duì)于爬蟲(chóng)來(lái)說(shuō),大部分操作時(shí)間都花在 IO 上,CPU 運(yùn)算的時(shí)間很少,,因此多線程還是很實(shí)用,。只有在 IO 操作時(shí),,線程才會(huì)主動(dòng)釋放掉 GIL,,對(duì)于爬蟲(chóng)操作來(lái)說(shuō),網(wǎng)絡(luò)請(qǐng)求和文件下載都屬于 IO 操作,。多線程最常見(jiàn)的用法是自定義 threading.Thread 的子類(lèi),,重寫(xiě) run() 方法,然后調(diào)用 start() 函數(shù)啟動(dòng)線程,。import threading import time
class thread1(threading.Thread):
def run(self): # IO操作1 pass
class thread2(threading.Thread): def run(self): # IO操作2 pass
if __name__ == '__main__': t1 = thread1() t2 = thread2()
t1.start() t2.start()
多線程都是在同一個(gè)進(jìn)程中運(yùn)行的,對(duì)于進(jìn)程中的全局變量也是共享的,。由于線程執(zhí)行的無(wú)序性,,多個(gè)線程如果要修改全局變量時(shí),可能導(dǎo)致臟數(shù)據(jù),,因此需要利用到線程鎖,。import threading
global_value = 0
# 線程鎖 thread_lock = threading.Lock()
def add_value(): # 全局變量 global global_value
# 上鎖 gLock.acquire()
# 修改全局變量的操作 pass
# 釋放鎖 gLock.release()
if __name__ == '__main__': # 定義兩個(gè)線程,同時(shí)去調(diào)用一個(gè)方法去改變?nèi)肿兞康闹?/span> thread1 = threading.Thread(target=add_value) thread2 = threading.Thread(target=add_value)
thread1.start() thread2.start()
|