**
執行緒(英語:thread)是作業系統能夠進行運算排程的最小單位。它被包含在程序之中,是程序中的實際運作單位。一條執行緒指的是程序中乙個單一順序的控制流,乙個程序中可以併發多個執行緒,每條執行緒並行執行不同的任務。(維基百科)
上面的解釋很抽象吧,我再解釋一下。當乙個程式啟動時,就會產生乙個程序或者多個程序,當乙個程序產生,同時也會產生乙個程序,這個程序就是主程序。而主程序還會產生子程序,這些子程序是可以同時進行的。
例如,有兩個這樣的程式:
def
a():
print('第乙個函式')
defb
(): print('第二個函式')
a()b()
上面的程式先執行函式a(),再執行函式b()。如果要用到程序的話,函式a()和函式b()可以同時進行。
** python提供了threading模組進行程序的調控。我們把上面的那段程式改寫成多程序的:
import threading
defa
(): print('第乙個函式\n')
defb
(): print('第二個函式\n')
th1=threading.thread(target=a)
th2=threading.thread(target=b)
th1.start()
th2.start()
執行結果:
>>> 第乙個函式
第二個函式
也有可能是:
>>> 第二個函式
第乙個函式
為什麼會出現這種狀況,為什麼呢?因為函式a()和函式b()是同時啟動的,執行時間差不多,所以有可能是a()先執行完,也有可能是b()先執行完。然後,我們再看看程序的形式th1=threading.thread(target=a),其中th1是子程序的名字,target鎖定函式,如果函式有引數怎麼辦?要寫成threading.thread(target=a,args=(x,x))這種形式。當把函式寫程序式後,就要啟動,th1.start()
這段程式不太能體現出線程的優點,我們再寫一段程式:
import threading,time
defa
(): print('a begin!')
print('a is running.........')
time.sleep(2)
print('a end!')
defb
(): print('b begin!')
print('b is running.........')
time.sleep(2)
print('b end!')
_time=time.time()
a()b()
print('共耗時%f秒'%(time.time()-_time))
執行結果:
a begin!
a is running.........
aend!
b begin!
b is running.........
b end!
共耗時4.058232秒
上面的**沒有寫成程序,所以共耗時4秒。我們把它寫成程序:
import threading,time
defa
(): print('a begin!')
print('a is running.........')
time.sleep(2)
print('a end!')
defb
(): print('b begin!')
print('b is running.........')
time.sleep(2)
print('b end!')
_time=time.time()
_a=threading.thread(target=a)
_b=threading.thread(target=b)
_a.start()
_b.start()
_b.join()
_b.join()
print('共耗時%f秒'%(time.time()-_time))
執行結果:
a begin!b begin!
a is running.........b is running.........
a end!b end!
共耗時2.073119秒
從上面的結果可以看出耗時2秒,節省了一半時間。join()函式是起到阻塞的作用,詳細用法見我的部落格:python多執行緒中join和setdaemon的用法。
** 先寫個例項程式:
import threading,time
num=0
defa
(n):
global num
num=num+n
num=num-n
defchange
(n):
for i in range(100000):
a(n)
t1=threading.thread(target=change,args=(5,))
t2=threading.thread(target=change,args=(8,))
t1.start()
t2.start()
t1.join()
t2.join()
print(num)
在上面**中,執行函式change(),根據我們的演算法,無論函式的引數是多少,執行多少次,num的結果應該始終是零。但是執行結果如下:
13
或者:
-2
這是為什麼呢?num是全域性變數,在同一程序下的執行緒之間的變數是共享的,所以,在t1和t2這兩個程序中都會對num進行操作。當執行到執行緒t1中num=num+你,應該接著執行t1程序中的num=num-1,但是程序都是同時進行的,所以會對num進行執行緒t2中的操作,num因此會出現其他值。為了避免多個程序同時對乙個變數或者檔案操作,python引進了互斥鎖:當乙個程序對乙個變數或乙個檔案進行操作時,會禁止其他程序對此變數或者檔案進行操作。我們可以將上面的**改寫如下:
import threading,time
num=0
mylock=threading.lock()
defa
(n):
global num
mylock.acquire()
num=num+n
num=num-n
mylock.release()
defchange
(n):
for i in range(100000):
a(n)
t1=threading.thread(target=change,args=(5,))
t2=threading.thread(target=change,args=(8,))
t1.start()
t2.start()
t1.join()
t2.join()
print(num)
這樣執行的結果始終是0。此外,只要加鎖就一定要解鎖,否則會形成死鎖,就是其他程序始終不能對變數進行操作。加鎖的位置只要能夠將變數包住就行,例如將鎖加在如下位置也可以:
def
change
(n):
for i in range(100000):
mylock.acquire()
a(n)
mylock.release()
**
在python中的多執行緒其實並不能真正利用多核cpu的優勢,這是因為在python中有乙個gil(global interpreter lock)。python在執行多執行緒程式時,其中乙個執行緒在執行前先獲gil,這樣其他的執行緒就不能執行。當第乙個執行緒執行了若干行**後再釋放gil,由另外乙個執行緒獲得gil並執行。由此可見,早python中多執行緒必不能有效的利用多核cpu的優勢。因此為了個好的有效利用多核cpu,所以我們可以建立多個多執行緒的程序。
python多執行緒 python多執行緒
通常來說,多程序適用於計算密集型任務,多執行緒適用於io密集型任務,如網路爬蟲。關於多執行緒和多程序的區別,請參考這個 下面將使用python標準庫的multiprocessing包來嘗試多執行緒的操作,在python中呼叫多執行緒要使用multiprocessing.dummy,如果是多程序則去掉...
python多執行緒詳解 Python多執行緒詳解
前言 由於最近的工作中一直需要用到python去處理資料,而在面對大量的資料時,python多執行緒的優勢就展現出來了。因而藉此機會,盡可能詳盡地來闡述python多執行緒。但對於其更底層的實現機制,在此不做深究,僅是對於之前的一知半解做個補充,也希望初學者能夠通過這篇文章,即便是照葫蘆畫瓢,也能夠...
python程式多執行緒 PYTHON多執行緒
在單執行緒的情況下,程式是逐條指令順序執行的。同一時間只做乙個任務,完成了乙個任務再進行下乙個任務。比如有5個人吃飯,單執行緒一次只允許乙個人吃,乙個人吃完了另乙個人才能接著吃,假如每個人吃飯都需要1分鐘,5個人就需要5分鐘。多執行緒的情況下,程式就會同時進行多個任務,雖然在同一時刻也只能執行某個任...