東莞公司網(wǎng)站建設(shè)公司河南網(wǎng)站顧問
目錄
- 一、知識點(diǎn)
- 二、多線程語法
- GIL
- 單線程
- 多線程
- 單線程
- 多線程
- 最后的驚喜
一、知識點(diǎn)
線程(Thread)也叫輕量級進(jìn)程,是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位,它被包含在進(jìn)程之中,是進(jìn)程中的實(shí)際運(yùn)作單位。線程自己不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的資源,但它可與同屬的一個(gè)進(jìn)程的其它線程共享進(jìn)程所擁有的全部資源。一個(gè)線程可以創(chuàng)建和撤銷另一個(gè)線程,同一進(jìn)程中的多個(gè)線程之間可以并發(fā)執(zhí)行。
二、多線程語法
在Python中實(shí)現(xiàn)多線程編程需要用到的就是threading模塊中的Thread類,我們來看看最簡單的語法,我們首先來一個(gè)簡單的函數(shù)。
def task(num):count = 0for i in range(num):count += 1print(count)nums = [100, 1000, 10000]
for num in nums:task(num)# 100
#1000
#10000
我們用三個(gè)子線程分別計(jì)算。
import threadingdef task(num):count = 0for i in range(num):count += 1print(count)nums = [100, 1000, 10000]
for num in nums:t = threading.Thread(target=task, args=(num,))t.start()
利用Thread創(chuàng)建線程,target參數(shù)接收函數(shù)名,args參數(shù)接收函數(shù)的參數(shù),start方法啟動線程。
這里還需要講解一下join方法,他的作用是讓主線程等待,直到該子線程結(jié)束。我們來看看加該方法和不加該方法,最終的結(jié)果是怎么樣的。
import threadingdef task():num = 0for i in range(10000000):num += 1print(num)t = threading.Thread(target=task)
t.start()
print('end')# end
# 10000000import threadingdef task():num = 0for i in range(10000000):num += 1print(num)t = threading.Thread(target=task)
t.start()
t.join()
print('end')# 10000000
# end
GIL
在說概念之前,我們還是以上面的代碼為例,分別求單線程和多線程代碼運(yùn)行的時(shí)間。
單線程
import timedef task(num):count = 0for i in range(num):count += 1print(count)nums = [1000000, 100000000, 1000000000]
start = time.time()
for num in nums:task(num)
end = time.time()
print(end - start)# 50.44705629348755
多線程
import threading
import timedef task(num):count = 0for i in range(num):count += 1print(count)nums = [1000000, 100000000, 1000000000]
ts = []
start = time.time()for num in nums:t = threading.Thread(target=task, args=(num,))t.start()ts.append(t)for t in ts:t.join()end = time.time()
print(end - start)# 55.022353172302246
你會發(fā)現(xiàn)多線程比單線程花費(fèi)的時(shí)間還要更多,這是因?yàn)镚IL的原因。
GIL的全稱是Global Interpreter Lock(全局解釋器鎖),Python最初的設(shè)計(jì)理念在于,為了解決多線程之間數(shù)據(jù)完整性和狀態(tài)同步的問題,設(shè)計(jì)為在任意時(shí)刻只能由一個(gè)線程在解釋器中運(yùn)行。因此Python中的多線程是表面上的多線程(同一時(shí)刻只有一個(gè)線程),不是真正的多線程。
但是如果是因?yàn)镚IL的原因,就說多線程無用是不對的,對于IO密集的程序,多線程是要比單線程快的。我們舉一個(gè)簡單的爬蟲案例。
單線程
import timedef task(url):s = url.split('_')[-1]time.sleep(int(s)) #這里模擬請求等待urls = ['url_1', 'url_2', 'url_3']
start = time.time()
for url in urls:task(url)
end = time.time()
print(end - start)# 6.013520002365112
多線程
import threading
import timedef task(url):s = url.split('_')[-1]time.sleep(int(s))ts = []
urls = ['url_1', 'url_2', 'url_3']
start = time.time()for url in urls:t = threading.Thread(target=task, args=(url,))t.start()ts.append(t)for t in ts:t.join()end = time.time()
print(end - start)# 3.005527973175049
這時(shí)候我們就能看到多線程的優(yōu)勢了,雖然多線程只是在各線程來回切換,但是可以讓IO堵塞的時(shí)間切換到其他線程做其他的任務(wù),很適合爬蟲或者文件的操作。
最后的驚喜
最后這里有準(zhǔn)備一些Python的學(xué)習(xí)資料需要的自取哈