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

Python 多線(xiàn)程超詳細(xì)到位總結(jié)

 更新時(shí)間:2021年11月03日 16:27:36   作者:Python學(xué)習(xí)與數(shù)據(jù)挖掘  
線(xiàn)程在程序中是獨(dú)立的、并發(fā)的執(zhí)行流。與分隔的進(jìn)程相比,進(jìn)程中線(xiàn)程之間的隔離程度要小,它們共享內(nèi)存、文件句柄和其他進(jìn)程應(yīng)有的狀態(tài)。線(xiàn)程的劃分尺度小于進(jìn)程,使多線(xiàn)程程序的并發(fā)性高。進(jìn)程在執(zhí)行過(guò)程中擁有獨(dú)立內(nèi)存單元,而多個(gè)線(xiàn)程共享內(nèi)存,從而提升程序運(yùn)行效率

在實(shí)際處理數(shù)據(jù)時(shí),因系統(tǒng)內(nèi)存有限,我們不可能一次把所有數(shù)據(jù)都導(dǎo)出進(jìn)行操作,所以需要批量導(dǎo)出依次操作。為了加快運(yùn)行,我們會(huì)采用多線(xiàn)程的方法進(jìn)行數(shù)據(jù)處理,以下為我總結(jié)的多線(xiàn)程批量處理數(shù)據(jù)的模板:

import threading
# 從數(shù)據(jù)庫(kù)提取數(shù)據(jù)的類(lèi)
class Scheduler():
    def __init__(self):
        self._lock = threading.RLock()
        self.start = 0
        # 每次取10000條數(shù)據(jù)
        self.step = 10000

    def getdata(self):
        # 上鎖,以免多線(xiàn)程同時(shí)對(duì)數(shù)據(jù)庫(kù)進(jìn)行訪(fǎng)問(wèn),取出重復(fù)數(shù)據(jù)
        self._lock.acquire()
        # 進(jìn)行取數(shù)據(jù)操作
        data = 'select * from table' \
               'where id between self.start and self.start + self.step'
        # 取完數(shù)據(jù)后,指針后移
        self.start += self.step
        self._lock.release()
        return data

# 處理數(shù)據(jù)的過(guò)程寫(xiě)在這里
def processdata():
    # 從該實(shí)例中提取數(shù)據(jù)
    data = scheduler.getdata()
    while data:
        # 進(jìn)行處理數(shù)據(jù)的具體操作:
        # 去重、補(bǔ)缺、運(yùn)算...只要還有數(shù)據(jù),本線(xiàn)程就繼續(xù)取新數(shù)據(jù)
        # 然后再獲取數(shù)據(jù),進(jìn)行循環(huán)
        data = scheduler.getdata()

# 創(chuàng)建多線(xiàn)程,threads_num為創(chuàng)建的線(xiàn)程數(shù)
def threads_scheduler(threads_num):
    threads = []
    for i in range(threads_num):
        # 創(chuàng)建線(xiàn)程
        td = threading.Thread(target=processdata, name='th'+str(i+1))
        threads.append(td)
    for t in threads:
        # 啟動(dòng)線(xiàn)程
        t.start()
        for t in threads:
            # 子線(xiàn)程守護(hù)
            t.join()
            print('數(shù)據(jù)已全部處理成功')

if __name__=='__main__':
    # 實(shí)例化一個(gè)調(diào)度器,初始化參數(shù)
    scheduler = Scheduler()
    # 創(chuàng)建線(xiàn)程,開(kāi)始處理數(shù)據(jù)
    threads_scheduler(4)

主要分為三大部分:

  • Scheduler類(lèi),負(fù)責(zé)初始化參數(shù),getdata方法負(fù)責(zé)提取數(shù)據(jù)
  • processdata方法中寫(xiě)具體處理數(shù)據(jù)的流程
  • threads_scheduler方法負(fù)責(zé)創(chuàng)建線(xiàn)程

Python多線(xiàn)程的知識(shí)我分為4部分進(jìn)行講解,以下帶大家來(lái)回顧重點(diǎn):

多線(xiàn)程threading

本章先為大家介紹了線(xiàn)程的相關(guān)概念:

主線(xiàn)程:當(dāng)一個(gè)程序啟動(dòng)時(shí),就有一個(gè)進(jìn)程被操作系統(tǒng)(OS)創(chuàng)建,與此同時(shí)一個(gè)線(xiàn)程也立刻運(yùn)行,該線(xiàn)程通常叫做程序的主線(xiàn)程(Main Thread)。因?yàn)樗浅绦蜷_(kāi)始時(shí)就執(zhí)行的,如果你需要再創(chuàng)建線(xiàn)程,那么創(chuàng)建的線(xiàn)程就是這個(gè)主線(xiàn)程的子線(xiàn)程。

子線(xiàn)程:使用threading、ThreadPoolExecutor創(chuàng)建的線(xiàn)性均為子線(xiàn)程。

主線(xiàn)程的重要性體現(xiàn)在兩方面:1.是產(chǎn)生其他子線(xiàn)程的線(xiàn)程;2.通常它必須最后完成執(zhí)行,比如執(zhí)行各種關(guān)閉動(dòng)作。

在飛車(chē)程序中,如果沒(méi)有多線(xiàn)程,我們就不能一邊聽(tīng)歌一邊玩飛車(chē),聽(tīng)歌與玩游戲不能并行;在使用多線(xiàn)程后,我們就可以在玩游戲的同時(shí)聽(tīng)背景音樂(lè)。在這個(gè)例子中啟動(dòng)飛車(chē)程序就是一個(gè)進(jìn)程,玩游戲和聽(tīng)音樂(lè)是兩個(gè)線(xiàn)程。

Python提供了threading模塊來(lái)實(shí)現(xiàn)多線(xiàn)程:threading.Thread可以創(chuàng)建線(xiàn)程;setDaemon(True)為守護(hù)主線(xiàn)程,默認(rèn)為False;join()為守護(hù)子線(xiàn)程。

from time import sleep
import threading

def music(music_name):
    for i in range(2):
        print('正在聽(tīng){}'.format(music_name))
        sleep(1)
        print('music over')

def game(game_name):
    for i in range(2):
        print('正在玩{}'.format(game_name))
        sleep(3)
        print('game over')

threads = []
t1 = threading.Thread(target=music,args=('稻香',))
threads.append(t1)
t2 = threading.Thread(target=game,args=('飛車(chē)',))
threads.append(t2)

if __name__ == '__main__':
    for t in threads:
        # t.setDaemon(True)
        t.start()
        
    for t in threads:
        t.join()
    print('主線(xiàn)程運(yùn)行結(jié)束')

線(xiàn)程池

因?yàn)樾陆ň€(xiàn)程系統(tǒng)需要分配資源、終止線(xiàn)程系統(tǒng)需要回收資源,所以如果可以重用線(xiàn)程,則可以減去新建/終止的開(kāi)銷(xiāo)以提升性能。同時(shí),使用線(xiàn)程池的語(yǔ)法比自己新建線(xiàn)程執(zhí)行線(xiàn)程更加簡(jiǎn)潔。

Python為我們提供了ThreadPoolExecutor來(lái)實(shí)現(xiàn)線(xiàn)程池,此線(xiàn)程池默認(rèn)子線(xiàn)程守護(hù)。它的適應(yīng)場(chǎng)景為突發(fā)性大量請(qǐng)求或需要大量線(xiàn)程完成任務(wù),但實(shí)際任務(wù)處理時(shí)間較短。

from time import sleep
# fun為定義的待運(yùn)行函數(shù)
with ThreadPoolExecutor(max_workers=5) as executor:
    ans = executor.map(fun, [遍歷值])
    for res in ans:
        print(res)

with ThreadPoolExecutor(max_workers=5) as executor:
    list = [遍歷值]
    ans = [executor.submit(fun, i) for i in list]
    for res in as_completed(ans):
        print(res.result())

其中max_workers為線(xiàn)程池中的線(xiàn)程個(gè)數(shù),常用的遍歷方法有map和submit+as_completed。根據(jù)業(yè)務(wù)場(chǎng)景的不同,若我們需要輸出結(jié)果按遍歷順序返回,我們就用map方法,若想誰(shuí)先完成就返回誰(shuí),我們就用submit+as_complete方法。

線(xiàn)程互斥

我們把一個(gè)時(shí)間段內(nèi)只允許一個(gè)線(xiàn)程使用的資源稱(chēng)為臨界資源,對(duì)臨界資源的訪(fǎng)問(wèn),必須互斥的進(jìn)行?;コ猓卜Q(chēng)間接制約關(guān)系。線(xiàn)程互斥指當(dāng)一個(gè)線(xiàn)程訪(fǎng)問(wèn)某臨界資源時(shí),另一個(gè)想要訪(fǎng)問(wèn)該臨界資源的線(xiàn)程必須等待。當(dāng)前訪(fǎng)問(wèn)臨界資源的線(xiàn)程訪(fǎng)問(wèn)結(jié)束,釋放該資源之后,另一個(gè)線(xiàn)程才能去訪(fǎng)問(wèn)臨界資源。鎖的功能就是實(shí)現(xiàn)線(xiàn)程互斥。

我把線(xiàn)程互斥比作廁所包間上大號(hào)的過(guò)程,因?yàn)榘g里只有一個(gè)坑,所以只允許一個(gè)人進(jìn)行大號(hào)。當(dāng)?shù)谝粋€(gè)人要上廁所時(shí),會(huì)將門(mén)上上鎖,這時(shí)如果第二個(gè)人也想大號(hào),那就必須等第一個(gè)人上完,將鎖解開(kāi)后才能進(jìn)行,在這期間第二個(gè)人就只能在門(mén)外等著。這個(gè)過(guò)程與代碼中使用鎖的原理如出一轍,這里的坑就是臨界資源。

Python 的 threading 模塊引入了鎖。threading 模塊提供了 Lock 類(lèi),它有如下方法加鎖和釋放鎖:

  • acquire():對(duì) Lock加鎖,其中timeout參數(shù)指定加鎖多少秒
  • release():釋放鎖
class Account:
    def __init__(self, card_id, balance):
        # 封裝賬戶(hù)ID、賬戶(hù)余額的兩個(gè)變量
        self.card_id= card_id
        self.balance = balance
        
def withdraw(account, money):
    # 進(jìn)行加鎖
    lock.acquire()
    # 賬戶(hù)余額大于取錢(qián)數(shù)目
    if account.balance >= money:
        # 吐出鈔票
        print(threading.current_thread().name + "取錢(qián)成功!吐出鈔票:" + str(money),end=' ')
        # 修改余額
        account.balance -= money
        print("\t余額為: " + str(account.balance))
    else:
        print(threading.current_thread().name + "取錢(qián)失敗!余額不足")
    # 進(jìn)行解鎖
    lock.release()
# 創(chuàng)建一個(gè)賬戶(hù),銀行卡id為8888,存款1000元
acct = Account("8888" , 1000)

# 模擬兩個(gè)對(duì)同一個(gè)賬戶(hù)取錢(qián)
# 在主線(xiàn)程中創(chuàng)建一把鎖
lock = threading.Lock()
threading.Thread(name='窗口A(yíng)', target=withdraw , args=(acct , 800)).start()
threading.Thread(name='窗口B', target=withdraw , args=(acct , 800)).start()

lock與Rlock的區(qū)別

區(qū)別一:Lock被稱(chēng)為原始鎖,一個(gè)線(xiàn)程只能請(qǐng)求一次;RLock被稱(chēng)為重入鎖,可以被一個(gè)線(xiàn)程請(qǐng)求多次,即鎖中可以嵌套鎖。

import threading

def main():
    lock.acquire()
    print('第一道鎖')
    lock.acquire()
    print('第二道鎖')
    lock.release()
    lock.release()
    
if __name__ == '__main__':
    lock = threading.Lock()
    main()

我們會(huì)發(fā)現(xiàn)這個(gè)程序只會(huì)打印“第一道鎖”,而且程序既沒(méi)有終止,也沒(méi)有繼續(xù)運(yùn)行。這是因?yàn)長(zhǎng)ock鎖在同一線(xiàn)程內(nèi)第一次加鎖之后還沒(méi)有釋放時(shí),就進(jìn)行了第二次acquire請(qǐng)求,導(dǎo)致無(wú)法執(zhí)行release,所以鎖永遠(yuǎn)無(wú)法釋放,這就是死鎖。如果我們使用RLock就能正常運(yùn)行,不會(huì)發(fā)生死鎖的狀態(tài)。

區(qū)別二:當(dāng)Lock處于鎖定狀態(tài)時(shí),不屬于特定線(xiàn)程,可在另一個(gè)線(xiàn)程中進(jìn)行解鎖釋放;而RLock只有當(dāng)前線(xiàn)程才能釋放本線(xiàn)程上的鎖,不可由其他線(xiàn)程進(jìn)行釋放,所以在使用RLock時(shí),acquire與release必須成對(duì)出現(xiàn),即解鈴還須系鈴人。

import threading

def main():
    lock.release()
    print("在子線(xiàn)程解鎖后打印")
if __name__ == '__main__':
    lock = threading.Lock()
    lock.acquire()
    t = threading.Thread(target=main)
    t.start()

在主線(xiàn)程中定義Lock鎖,然后上鎖,再創(chuàng)建一個(gè)子線(xiàn)程t運(yùn)行main函數(shù)釋放鎖,結(jié)果正常輸出,說(shuō)明主線(xiàn)程上的鎖,可由子線(xiàn)程解鎖。

如果把上面的鎖改為RLock則報(bào)錯(cuò)。在實(shí)際中設(shè)計(jì)程序時(shí),我們會(huì)將每個(gè)功能分別封裝成一個(gè)函數(shù),每個(gè)函數(shù)中都可能會(huì)有臨界區(qū)域,所以就需要用到RLock。

import threading
import time

def fun_1():
    print('開(kāi)始')
    time.sleep(1)
    lock.acquire()
    print("第一道鎖")
    fun_2()
    lock.release()
    
def fun_2():
    lock.acquire()
    print("第二道鎖")
    lock.release()
    
if __name__ == '__main__':
    lock = threading.RLock()
    t1 = threading.Thread(target=fun_1)
    t2 = threading.Thread(target=fun_1)
    t1.start()
    t2.start()

一句話(huà)總結(jié)就是Lock不能套娃,RLock可以套娃;Lock可以由其他線(xiàn)程中的鎖進(jìn)行操作,RLock只能由本線(xiàn)程進(jìn)行操作。

以上就是多線(xiàn)程所有內(nèi)容,喜歡的小伙伴支持,收藏。

技術(shù)交流

歡迎轉(zhuǎn)載、收藏、有所收獲點(diǎn)贊支持一下!

在這里插入圖片描述

到此這篇關(guān)于Python 多線(xiàn)程超詳細(xì)到位總結(jié)的文章就介紹到這了,更多相關(guān)Python 多線(xiàn)程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • python異常的捕捉和補(bǔ)救實(shí)例詳解

    python異常的捕捉和補(bǔ)救實(shí)例詳解

    在本篇文章里小編給大家整理的是一篇關(guān)于python異常的捕捉和補(bǔ)救實(shí)例詳解內(nèi)容,有需要的朋友們可以跟著學(xué)習(xí)參考下。
    2021-06-06
  • Python使用MONGODB入門(mén)實(shí)例

    Python使用MONGODB入門(mén)實(shí)例

    這篇文章主要介紹了Python使用MONGODB的方法,實(shí)例分析了Python使用MONGODB的啟動(dòng)、安裝及使用的相關(guān)技巧,需要的朋友可以參考下
    2015-05-05
  • python數(shù)據(jù)分析實(shí)戰(zhàn)指南之異常值處理

    python數(shù)據(jù)分析實(shí)戰(zhàn)指南之異常值處理

    數(shù)據(jù)預(yù)處理是明確分析目標(biāo)與思路之后進(jìn)行數(shù)據(jù)分析的第一步,也是整個(gè)項(xiàng)目中最基礎(chǔ)、花費(fèi)時(shí)間較長(zhǎng)的工作,下面這篇文章主要給大家介紹了關(guān)于python數(shù)據(jù)分析實(shí)戰(zhàn)指南之異常值處理的相關(guān)資料,需要的朋友可以參考下
    2022-01-01
  • 如何教少兒學(xué)習(xí)Python編程

    如何教少兒學(xué)習(xí)Python編程

    在本篇文章里小編給大家整理了關(guān)于教少兒學(xué)習(xí)Python編程的相關(guān)文章及知識(shí)點(diǎn),需要的朋友們可以參考下。
    2020-07-07
  • python3.5使用tkinter制作記事本

    python3.5使用tkinter制作記事本

    TkInter是標(biāo)準(zhǔn)的Python GUI庫(kù)。的Python與Tkinter的結(jié)合提供了一個(gè)快速和容易的方法來(lái)創(chuàng)建GUI應(yīng)用程序。 Tkinter的提供了一個(gè)強(qiáng)大的面向?qū)ο蟮慕涌赥k的GUI工具包.
    2016-06-06
  • python編程webpy框架模板之def with學(xué)習(xí)

    python編程webpy框架模板之def with學(xué)習(xí)

    這篇文章主要為大家介紹了python編程web.py框架模板之def with的學(xué)習(xí)有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2021-11-11
  • Python編程matplotlib繪圖挑鉆石seaborn小提琴和箱線(xiàn)圖

    Python編程matplotlib繪圖挑鉆石seaborn小提琴和箱線(xiàn)圖

    這篇文章主要為大家介紹了Python編程如何使用matplotlib繪圖來(lái)挑出完美的鉆石以及seaborn小提琴和箱線(xiàn)圖,有需要的朋友可以借鑒參考下,希望能夠優(yōu)速幫助
    2021-10-10
  • 將python安裝信息加入注冊(cè)表的示例

    將python安裝信息加入注冊(cè)表的示例

    今天小編就為大家分享一篇將python安裝信息加入注冊(cè)表的示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-11-11
  • Ubuntu配置Python環(huán)境的超詳細(xì)教程

    Ubuntu配置Python環(huán)境的超詳細(xì)教程

    這篇文章主要給大家介紹了關(guān)于Ubuntu配置Python環(huán)境的超詳細(xì)教程,文中通過(guò)代碼示例將配置的過(guò)程介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Python具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2023-08-08
  • Python獲取服務(wù)器信息的最簡(jiǎn)單實(shí)現(xiàn)方法

    Python獲取服務(wù)器信息的最簡(jiǎn)單實(shí)現(xiàn)方法

    這篇文章主要介紹了Python獲取服務(wù)器信息的最簡(jiǎn)單實(shí)現(xiàn)方法,涉及Python中urllib2庫(kù)的使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-03-03

最新評(píng)論

友谊县| 康保县| 定边县| 日照市| 黑龙江省| 井陉县| 翁源县| 十堰市| 肇东市| 防城港市| 靖州| 互助| 抚松县| 合山市| 丹棱县| 屏山县| 昆明市| 张家川| 六盘水市| 镇沅| 马龙县| 德阳市| 长汀县| 通化县| 乐业县| 长宁县| 垫江县| 灵石县| 平罗县| 仙居县| 保靖县| 磐石市| 广安市| 务川| 武夷山市| 景泰县| 调兵山市| 雷州市| 施甸县| 长春市| 南宫市|