最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python學習之線程池與GIL全局鎖詳解

 更新時間:2022年04月13日 09:58:44   作者:渴望力量的哈士奇  
本文我們將學習線程池的創(chuàng)建與全局鎖。線程池的創(chuàng)建于進程池的原理是相同的;關(guān)于GIL全局鎖,暫時沒有代碼上的練習,而是對其概念進行一個簡單的啟蒙,感興趣的可以了解一下

線程池

線程池的創(chuàng)建 - concurrent

concurrent 是 Python 的內(nèi)置包,使用它可以幫助我們完成創(chuàng)建線程池的任務。

方法名介紹示例
futures.ThreadPoolExecutor創(chuàng)建線程池tpool=ThreadPoolExecutor(max_workers)

通過調(diào)用 concurrent 包的 futures 模塊的 ThreadPoolExecutor 類,通過實例化 ThreadPoolExecutor 實現(xiàn)創(chuàng)建線程池的對象,它有一個參數(shù)來設(shè)置 線程池的數(shù)量。這和創(chuàng)建進程池設(shè)置的數(shù)量是完全相同的。

線程池的常用方法

接下里看一下線程池對象中都有哪些常用的方法 :

函數(shù)名介紹用法
submit往線程池中添加任務submit(target, args)
done確認線程池中的某個線程是否完成了任務done()
rsult獲取當前線程執(zhí)行任務的結(jié)果result()
  • submit 函數(shù):通過 submit 函數(shù)將參數(shù)傳入;該函數(shù)傳入的參數(shù)也是傳入要執(zhí)行的函數(shù)與該函數(shù)的參數(shù),由于它的參數(shù)并不用需要通過賦值語句的形式傳入,只需要把相應的值傳入就可以了(稍后會進行一個練習)。
  • done 函數(shù):判斷當前線程是否執(zhí)行完成;返回值是 bool 類型。
  • result 函數(shù):返回當前線程池中線程任務的執(zhí)行結(jié)果,通過這種方法就可以獲取線程池的返回值了。

線程池演示案例

1、定義一個函數(shù)實現(xiàn)循環(huán)的效果

2、定義一個線程池,設(shè)置線程的數(shù)量

# coding:utf-8


import time
from concurrent.futures import ThreadPoolExecutor


def work(i):
    print('第 {} 次循環(huán)'.format(i))
    time.sleep(1)   # 之所以每次都要使用 sleep 函數(shù),是因為函數(shù)執(zhí)行太快;通過 sleep 嘗試模擬一下長時間的執(zhí)行一個任務


if __name__ == '__main__':
    thread_poor = ThreadPoolExecutor(4)	# 實例化一個線程池,設(shè)置線程數(shù)量為4

    for i in range(20):
        thread_poor.submit(work, (i,))		# 利用 submit 函數(shù)將任務添加至 work 函數(shù)

運行效果如下 

從運行結(jié)果來看,我們的線程任務每次執(zhí)行4個任務,阻塞一秒后再執(zhí)行后續(xù)的四個線程的任務,是沒有問題的。

PS:需要注意的是,運行結(jié)果有可能是出現(xiàn)將兩個或者多個任務的結(jié)果在同一行打印輸出,這是因為在同一時間處理了多個線程的任務,這也叫 "并發(fā)"。

線程鎖

前文的進程池是與進程鎖相對應匹配的,同樣的線程池也有與之對應的 線程鎖 。線程鎖的使用方法幾乎與進程鎖是一樣的,只不過線程鎖對應的是線程罷了。

1.實例化一個線程鎖

2、在 work 函數(shù)中調(diào)用線程鎖

3、并獲取 線程 的返回值(線程池也是可以獲取返回值的)

代碼示例如下:

 # coding:utf-8


import os
import time
import threading
from concurrent.futures import ThreadPoolExecutor


lock = threading.Lock()     # 全局定義一個 Lock() 實例

def work(i):
    lock.acquire()          # 區(qū)別于 進程鎖 只需要在全局實例化一個即可,線程鎖需要在線程任務的函數(shù)中調(diào)用 線程鎖 才會生效
    print('當前是第 {} 次循環(huán)'.format(i))
    time.sleep(1)           # 之所以每次都要使用 sleep 函數(shù),是因為函數(shù)執(zhí)行太快;通過 sleep 嘗試模擬一下長時間的執(zhí)行一個任務
    lock.release()
    return '第 {} 次循環(huán)的進程id為:{}'.format(i, os.getpid())    # 線程也是基于進程實現(xiàn)的


if __name__ == '__main__':
    thread_poor = ThreadPoolExecutor(4)    # 實例化一個線程池,設(shè)置線程數(shù)量為4

    result = []

    for i in range(20):
        result_thread = thread_poor.submit(work, (i,))      # 利用 submit 函數(shù)將任務添加至 work 函數(shù);
                                                            # 需要注意的是這里不像進程池那樣使用賦值的形式傳入 work 函數(shù)
        result.append(result_thread)

    for res in result:
        print(res.result())

運行結(jié)果如下:

從運行結(jié)果可以看到,之前一同執(zhí)行的4個任務現(xiàn)在變成了一次只執(zhí)行一個任務;每一個個線程都是在主進程 93215下執(zhí)行的,說明線程與進程還是有所區(qū)別的,雖然我們有多個線程任務在執(zhí)行,但是依然是在主進程下去完成的;同時我們還獲取到了 線程的返回值 第 {} 次循環(huán)的進程id為:{}'.format(i, os.getpid() 。

以上就是線程池的使用和常用方法,我們會發(fā)現(xiàn)線程池的使用實際上要比進程池的使用要容易一些。進程池我們需要考慮 join 與 close 等一些問題,但是線程池則不需要那么的嚴格,并且線程相對于進程要更加的輕量,使用起來也更加的便捷。

利用線程池實現(xiàn)抽獎小案例

案例代碼如下:

# coding:utf-8

import threading
import random
from concurrent.futures import ThreadPoolExecutor

lock = threading.Lock()
def luck_draw(arg):
    lock.acquire()
    # 從手機列表中隨機選出一個中獎手機,其他手機均未中獎
    phone = random.choice(arg[0])
    # 在從獎池中隨機選取一個獎品,視為該手機抽中的獎品
    price = random.choice(arg[1])
    prices.remove(price)
    phones.remove(phone)
    lock.release()
    return '恭喜手機尾號為{}的用戶,抽到{}'.format(str(phone)[-5:-1], price)


if __name__ == '__main__':
    t = ThreadPoolExecutor(3)       # 通過創(chuàng)建三個線程從而實現(xiàn)每個線程完成一項抽獎任務
    # 確定抽獎人數(shù)
    phone_num = int(input('請輸入抽獎的用戶人數(shù):'))
    # 模擬產(chǎn)生出相應數(shù)量的手機號
    phones = random.sample(range(13300000000, 19999999999), phone_num)      # 這里設(shè)置的隨機號碼僅做演示效果
    prices = ['一等獎:iPhone12 ProMax', '二等獎:ipad2021pro', '三等獎:air wetter']
    result = []
    for i in range(3): # 三個任務,每個線程分配一個
        t_result = t.submit(luck_draw, (phones, prices))
        result.append(t_result)

    for res in result:
        print(res.result())

運行效果如下:

GIL全局鎖

本章節(jié)的開頭我們就說過,該部分沒有代碼的相關(guān)練習。僅僅是對 GIL全局鎖 做一個概念上的簡單啟蒙。

其他語言的線程與Python線程的區(qū)別

多線程與多進程的使用其實是比較復雜的,目前作為初學者來說涉及的還比較淺。最近的幾個章節(jié)介紹了 進程與線程在CPU的執(zhí)行方式,這里再進行拓展一下。

下面我們看一張圖:

依然是一個CPU 與4個核心(可以認為是4條跑道);

先看左邊的兩條跑道,是進程1創(chuàng)建的3個線程。這三條線程有一個去了 1core 跑道,另外兩條則去了 2core 跑道。線程之間有選擇性的進入了不同的跑道,當然進程1的主進程或者說是主線程可能會在 1core 跑道、也可能會在 2core 跑道,這是其他語言進行多線程的樣子。

再來看看右邊,Python 創(chuàng)建的進程2。當進程創(chuàng)建之后,包含主線程一共產(chǎn)生了3個線程,而這三個線程都跑到了 4core 跑道 上去。它不會像其他語言那樣去尋找不同的有空閑資源的跑道去執(zhí)行,而是僅僅在主進程所處的跑道去執(zhí)行線程。造成 Python 中的多線程無法在多條跑道執(zhí)行任務的主要原因就是因為 GIL全局鎖 ,這個 GIL 并不是 Python語法中添加上去的,而是 python解釋器 在執(zhí)行的時候自動加了這把 "鎖" 。

GIL 的作用

因為 GIL 鎖 的關(guān)系,使得 Python 的多線程無法在多個CPU跑道上去執(zhí)行任務,它只能在單一CPU上進行工作。

這也限制了多線程的性能,畢竟 Python 的多線程只能在一條跑道上運行。跑道滿了,運行速度依然會慢。而在多個跑道上運行的任務必然是要比單一跑道效率會高很多。

Python創(chuàng)始人 Guido 之所以保留 GIL 鎖,其實也是為了線程之間的安全。雖然這個話題一直都在爭論,不過我們也有辦法去掉這個 GIL全局鎖。

默認的解釋器是 Python 自帶的解釋器,這里我們可以選擇一個叫做 pypy 的解釋器。通過它來執(zhí)行 Python 腳本是不含有 GIL全局鎖 的,但并不太推薦這種做法。

另外一種解決方法就是使用 多進程 + 多線程 的方式 來彌補這一短板上的問題,通過多進程在每個 CPU 跑道上執(zhí)行任務,并且每個進程的跑道上再去執(zhí)行多個線程。 ,讓它們在各自的時間片上去運行。這些用法會在后續(xù)的章節(jié)會介紹到,在此只需要了解即可。

以上就是Python學習之線程池與GIL全局鎖詳解的詳細內(nèi)容,更多關(guān)于Python線程池 GIL全局鎖的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • python 2.6.6升級到python 2.7.x版本的方法

    python 2.6.6升級到python 2.7.x版本的方法

    這篇文章主要介紹了python 2.6.6升級到python 2.7.x版本的方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-10-10
  • OpenCV?Python身份證信息識別過程詳解

    OpenCV?Python身份證信息識別過程詳解

    本篇文章使用OpenCV-Python和CnOcr來實現(xiàn)身份證信息識別的案例,本篇文章使用的Python版本為3.6,OpenCV-Python版本為3.4.1.15,如果是4.x版本的同學,可能會有一些Api操作不同,下面跟隨小編看下OpenCV?Python身份證信息識別過程
    2022-04-04
  • python模擬登錄百度代碼分享(獲取百度貼吧等級)

    python模擬登錄百度代碼分享(獲取百度貼吧等級)

    python模擬登錄百度,實現(xiàn)了登錄并讀取百度關(guān)注貼吧列表,百度登錄還是有點麻煩的,由于用的ssl,所以要先獲取token,然后再登錄,這個用finddle2分析下,還是比較好解決的
    2013-12-12
  • 一文帶你快速掌握Python LightGBM必備知識點

    一文帶你快速掌握Python LightGBM必備知識點

    LightGBM(Light Gradient Boosting Machine)是一種梯度提升樹算法的高效實現(xiàn),這篇文章為大家整理了十個LightGBM必備知識點,希望對大家有所幫助
    2023-06-06
  • Python實現(xiàn)將單張或多張圖片轉(zhuǎn)PDF

    Python實現(xiàn)將單張或多張圖片轉(zhuǎn)PDF

    這篇文章主要為大家詳細介紹了如何使用Python實現(xiàn)將單張或多張圖片轉(zhuǎn)PDF,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2025-11-11
  • Django Admin設(shè)置應用程序及模型順序方法詳解

    Django Admin設(shè)置應用程序及模型順序方法詳解

    這篇文章主要介紹了Django Admin設(shè)置應用程序及模型順序方法詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-04-04
  • Python編程-封裝,繼承與多態(tài)

    Python編程-封裝,繼承與多態(tài)

    這篇文章主要介紹了Python編程-封裝,繼承與多態(tài),文章主要目的解如何利用封裝保護屬性、掌握單繼承和多繼承、會重寫和調(diào)用父類方法
    理解多態(tài)的使用等相關(guān)介紹,需要的朋友可以參考一下
    2022-01-01
  • Pandas:Series和DataFrame刪除指定軸上數(shù)據(jù)的方法

    Pandas:Series和DataFrame刪除指定軸上數(shù)據(jù)的方法

    今天小編就為大家分享一篇Pandas:Series和DataFrame刪除指定軸上數(shù)據(jù)的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-11-11
  • uwsgi+nginx部署Django項目操作示例

    uwsgi+nginx部署Django項目操作示例

    這篇文章主要介紹了uwsgi+nginx部署Django項目操作,結(jié)合實例形式簡單介紹了uwsgi的概念、原理、安裝、項目創(chuàng)建、配置、調(diào)試運行等相關(guān)操作技巧,需要的朋友可以參考下
    2018-12-12
  • python PIL/cv2/base64相互轉(zhuǎn)換實例

    python PIL/cv2/base64相互轉(zhuǎn)換實例

    今天小編就為大家分享一篇python PIL/cv2/base64相互轉(zhuǎn)換實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-01-01

最新評論

永济市| 长治市| 平乐县| 富源县| 杨浦区| 鸡西市| 沙湾县| 兴城市| 陇川县| 丰原市| 枝江市| 平罗县| 左权县| 蕲春县| 砚山县| 辽源市| 会昌县| 保康县| 江西省| 洛阳市| 广东省| 汉寿县| 揭东县| 孝昌县| 闽清县| 上杭县| 舞钢市| 阿拉善左旗| 徐汇区| 武义县| 托里县| 革吉县| 南木林县| 祥云县| 会泽县| 利津县| 新密市| 乌鲁木齐县| 阜阳市| 潜江市| 同德县|