Python 多線程Threading初學教程

Python 多線程Threading初學教程

1.1 什麼是多線程 Threading

多線程可簡單理解為同時執行多個任務。

多進程和多線程都可以執行多個任務,線程是進程的一部分。線程的特點是線程之間可以共享內存和變數,資源消耗少(不過在Unix環境中,多進程和多線程資源調度消耗差距不明顯,Unix調度較快),缺點是線程之間的同步和加鎖比較麻煩。

1.2 添加線程 Thread

導入模塊

import threading

獲取已激活的線程數

threading.active_count()

查看所有線程信息

threading.enumerate()

查看現在正在運行的線程

threading.current_thread()

添加線程,threading.Thread()接收參數target代表這個線程要完成的任務,需自行定義

def thread_job():

print(This is a thread of %s % threading.current_thread())

def main():

thread = threading.Thread(target=thread_job,) # 定義線程

thread.start() # 讓線程開始工作

if __name__ == __main__:

main()

1.3 join 功能

因為線程是同時進行的,使用join功能可讓線程完成後再進行下一步操作,即阻塞調用線程,直到隊列中的所有任務被處理掉。

import threading

import time

def thread_job():

print(T1 start
)

for i in range(10):

time.sleep(0.1)

print(T1 finish
)

def T2_job():

print(T2 start
)

print(T2 finish
)

def main():

added_thread=threading.Thread(target=thread_job,name=T1)

thread2=threading.Thread(target=T2_job,name=T2)

added_thread.start()

#added_thread.join()

thread2.start()

#thread2.join()

print(all done
)

if __name__==__main__:

main()

例子如上所示,當不使用join功能的時候,結果如下圖所示:

當執行了join功能之後,T1運行完之後才運行T2,之後再運行print(『all done)

1.4 儲存進程結果 queue

queue是python標準庫中的線程安全的隊列(FIFO)實現,提供了一個適用於多線程編程的先進先出的數據結構,即隊列,用來在生產者和消費者線程之間的信息傳遞

(1)基本FIFO隊列

class queue.Queue(maxsize=0)

maxsize是整數,表明隊列中能存放的數據個數的上限,達到上限時,插入會導致阻塞,直至隊列中的數據被消費掉,如果maxsize小於或者等於0,隊列大小沒有限制

(2)LIFO隊列 last in first out後進先出

class queue.LifoQueue(maxsize=0)

(3)優先順序隊列

class queue.PriorityQueue(maxsize=0)

視頻中的代碼,看的還不是特別明白

import threading

import time

from queue import Queue

def job(l,q):

for i in range(len(l)):

l[i]=l[i]**2

q.put(l)

def multithreading():

q=Queue()

threads=[]

data=[[1,2,3],[3,4,5],[4,5,6],[5,6,7]]

for i in range(4):

t=threading.Thread(target=job,args=(data[i],q))

t.start()

threads.append(t)

for thread in threads:

thread.join()

results=[]

for _ in range(4):

results.append(q.get())

print(results)

if __name__==__main__:

multithreading()

運行結果如下所示

1.5 GIL 不一定有效率

Global Interpreter

Lock全局解釋器鎖,python的執行由python虛擬機(也成解釋器主循環)控制,GIL的控制對python虛擬機的訪問,保證在任意時刻,只有一個線程在解釋器中運行。在多線程環境中能,python虛擬機按照以下方式執行:

1.設置 GIL

2.切換到一個線程去運行

3.運行:

a.指定數量的位元組碼指令,或

b.線程主動讓出控制(可以調用time.sleep(0))

4.把線程設置為睡眠狀態

5.解鎖GIL

6.重複1-5

在調用外部代碼(如C/C++擴展函數)的時候,GIL將會被鎖定,直到這個函數結束為止(由於在這期間沒有python的位元組碼被運行,所以不會做線程切換)。

下面為視頻中所舉例的代碼,將一個數擴大4倍,分為正常方式、以及分配給4個線程去做,發現耗時其實並沒有相差太多量級。

import threading

from queue import Queue

import copy

import time

def job(l, q):

res = sum(l)

q.put(res)

def multithreading(l):

q = Queue()

threads = []

for i in range(4):

t = threading.Thread(target=job, args=(copy.copy(l), q), name=T%i % i)

t.start()

threads.append(t)

[t.join() for t in threads]

total = 0

for _ in range(4):

total += q.get()

print(total)

def normal(l):

total = sum(l)

print(total)

if __name__ == __main__:

l = list(range(1000000))

s_t = time.time()

normal(l*4)

print(normal: ,time.time()-s_t)

s_t = time.time()

multithreading(l)

print(multithreading: , time.time()-s_t)

運行結果為:

1.6 線程鎖 Lock

如果線程1得到了結果,想要讓線程2繼續使用1的結果進行處理,則需要對1lock,等到1執行完,再開始執行線程2。一般來說對share memory即對共享內存進行加工處理時會用到lock。

import threading

def job1():

global A, lock #全局變數

lock.acquire() #開始lock

for i in range(10):

A += 1

print(job1, A)

lock.release() #釋放

def job2():

global A, lock

lock.acquire()

for i in range(10):

A += 10

print(job2, A)

lock.release()

if __name__ == __main__:

lock = threading.Lock()

A = 0

t1 = threading.Thread(target=job1)

t2 = threading.Thread(target=job2)

t1.start()

t2.start()

t1.join()

t2.join()

運行結果如下所示:

總結

以上所述是小編給大家介紹的Python 多線程Threading初學教程,希望對大家有所幫助


推薦閱讀:

TAG:Python | Python入門 | Python教程 |