Python多線程(上)

前言

說起Python的多線程,很多人都嗤之以鼻,說Python的多線程是假的多線程,沒有用,或者說不好用,那本次就和大家一起來分享一下Python的多線程,看看是不是這樣的。

相關概念

線程(Thread)也叫輕量級進程,是操作系統能夠進行運算調度的最小單位,它被包含在進程之中,是進程中的實際運作單位。線程自己不擁有系統資源,只擁有一點在運行中必不可少的資源,但它可與同屬的一個進程的其它線程共享進程所擁有的全部資源。一個線程可以創建和撤銷另一個線程,同一進程中的多個線程之間可以併發執行。

多線程語法

在Python中實現多線程編程需要用到的就是threading模塊中的Thread類,我們來看看最簡單的語法,我們首先來一個簡單的函數。

def task(num):
    count = 0
    for i in range(num):
        count += 1
    print(count)


nums = [100, 1000, 10000]
for num in nums:
    task(num)

# 100
#1000
#10000

我們用三個子線程分別計算。

import threading


def task(num):
    count = 0
    for i in range(num):
        count += 1
    print(count)


nums = [100, 1000, 10000]
for num in nums:
    t = threading.Thread(target=task, args=(num,))
    t.start()

利用Thread創建線程,target參數接收函數名,args參數接收函數的參數,start方法啓動線程。

這裏還需要講解一下join方法,他的作用是讓主線程等待,直到該子線程結束。我們來看看加該方法和不加該方法,最終的結果是怎麼樣的。

import threading


def task():
    num = 0
    for i in range(10000000):
        num += 1
    print(num)


t = threading.Thread(target=task)
t.start()
print('end')

# end
# 10000000
import threading


def task():
    num = 0
    for i in range(10000000):
        num += 1
    print(num)


t = threading.Thread(target=task)
t.start()
t.join()
print('end')

# 10000000
# end

GIL

在說概念之前,我們還是以上面的代碼爲例,分別求單線程和多線程代碼運行的時間。

單線程

import time


def task(num):
    count = 0
    for i in range(num):
        count += 1
    print(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 time


def task(num):
    count = 0
    for i in range(num):
        count += 1
    print(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

你會發現多線程比單線程花費的時間還要更多,這是因爲GIL的原因。

GIL的全稱是Global Interpreter Lock(全局解釋器鎖),Python最初的設計理念在於,爲了解決多線程之間數據完整性和狀態同步的問題,設計爲在任意時刻只能由一個線程在解釋器中運行。因此Python中的多線程是表面上的多線程(同一時刻只有一個線程),不是真正的多線程。

但是如果是因爲GIL的原因,就說多線程無用是不對的,對於IO密集的程序,多線程是要比單線程快的。我們舉一個簡單的爬蟲案例。

單線程

import time


def 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 time


def 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

這時候我們就能看到多線程的優勢了,雖然多線程只是在各線程來回切換,但是可以讓IO堵塞的時間切換到其他線程做其他的任務,很適合爬蟲或者文件的操作。

今天的分享就到這了,如果我的文章對你有幫助,別忘了點贊,收藏,轉發,這對我有很大的幫助,我們下期再見~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章