欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python語法學(xué)習(xí)之進程池與進程鎖詳解

 更新時間:2022年04月11日 10:08:57   作者:渴望力量的哈士奇  
這篇文章主要為大家介紹了Python進程中兩個重要的知識點:進程池與進程鎖,文中通過示例詳細(xì)為大家講解了二者的使用,感興趣的可以了解下

NICE!大家好,在上一章節(jié),我們學(xué)習(xí)了 multiprocessing 模塊 的關(guān)于進程的創(chuàng)建與進場常用的方法的相關(guān)知識。 通過在一個主進程下創(chuàng)建多個子進程可以幫助我們加速程序的運行,并且提高工作效率。不過上一章節(jié)文末我們也說過進程的問題,由于每一個進程都會消耗 CPU 與 內(nèi)存 資源,這樣就不能無限的創(chuàng)建進程的問題,因為會造成內(nèi)存不足或者死機的情況。

為了解決這個問題我們可以使用多線程來替代,或者使用我們今天要學(xué)習(xí)的內(nèi)容 —> 進程池。不僅如此,我們在上一章節(jié)也說了另一個問題,多進程在同時修改一個文件的時候可能會存在問題,解決的方法就是給這一個文件進行 上鎖 。今天我們就來學(xué)習(xí)一下 進程池與進程鎖 ,看看它們都能幫助我們怎樣解決問題。

進程池

什么是進程池

上一章節(jié)關(guān)于進程的問題我們提到過,進程創(chuàng)建太多的情況下就會對資源消耗過大。為了避免出現(xiàn)這種情況,我們就需要固定進程的數(shù)量,這時候就需要進程池的幫助。

我們可以認(rèn)為進程池就是一個池子,在這個池子里提前創(chuàng)建好一定數(shù)量的進程。見下圖:

比如這個紅色矩形陣列就代表一個進程池子,在這個池子中有6個進程。這6個進程會伴隨進程池一起被創(chuàng)建,不僅如此,我們在學(xué)習(xí)面向?qū)ο蟮纳芷诘臅r候曾經(jīng)說過,每個實例化對象在使用完成之后都會被內(nèi)存管家回收。

我們的進程也會伴隨著創(chuàng)建與關(guān)閉的過程而被內(nèi)存管家回收,每一個都是如此,創(chuàng)建于關(guān)閉進程的過程也會消耗一定的性能。而進程池中的進程當(dāng)被創(chuàng)建之后就不會被關(guān)閉,可以一直被重復(fù)使用,從而避免了創(chuàng)建于關(guān)閉的資源消耗,也避免了創(chuàng)建于關(guān)閉的反復(fù)操作提高了效率。

當(dāng)然,當(dāng)我們執(zhí)行完程序進程池關(guān)閉的時候,進程也隨之關(guān)閉。

當(dāng)我們有任務(wù)需要被執(zhí)行的時候,會判斷當(dāng)前的進程池當(dāng)中有沒有空閑的進程(所謂空閑的進程其實就是進程池中沒有執(zhí)行任務(wù)的進程)。有進程處于空閑狀態(tài)的情況下,任務(wù)會找到進程執(zhí)行該任務(wù)。如果當(dāng)前進程池中的進程都處于非空閑狀態(tài),則任務(wù)就會進入等待狀態(tài),直到進程池中有進程處于空閑狀態(tài)才會進出進程池從而執(zhí)行該任務(wù)。

這就是進程池的作用。

進程池的創(chuàng)建模塊 - multiprocessing

創(chuàng)建進程池函數(shù) - Pool

函數(shù)名介紹參數(shù)返回值
Pool進程池的創(chuàng)建Processcount進程池對象

Pool功能介紹:通過調(diào)用 "multiprocessing" 模塊的 "Pool" 函數(shù)來幫助我們創(chuàng)建 "進程池對象" ,它有一個參數(shù) "Processcount" (一個整數(shù)),代表我們這個進程池中創(chuàng)建幾個進程。

進程池的常用方法

當(dāng)創(chuàng)建了進程池對象之后,我們要對它進程操作,讓我們來看一下都有哪些常用方法(函數(shù))。

函數(shù)名介紹參數(shù)返回值
apply_async任務(wù)加入進程池(異步)func,args
close關(guān)閉進程池
join等待進程池任務(wù)結(jié)束
  • apply_async 函數(shù):它的功能是將任務(wù)加入到進程池中,并且是通過異步實現(xiàn)的。異步 這個知識我們還沒有學(xué)習(xí),先不用關(guān)心它到底是什么意思。它有兩個參數(shù):func 與 agrs , func 是加入進程池中工作的函數(shù);args 是一個元組,代表著簽一個函數(shù)的參數(shù),這和我們創(chuàng)建并使用一個進程是完全一致的。
  • close 函數(shù):當(dāng)我們使用完進程池之后,通過調(diào)用 close 函數(shù)可以關(guān)閉進程池。它沒有任何的參數(shù),也沒有任何的返回值。
  • join 函數(shù):它和我們上一章節(jié)學(xué)習(xí)的 創(chuàng)建進程的 join 函數(shù)中方法是一致的。只有進程池中的任務(wù)全部執(zhí)行完畢之后,才會執(zhí)行后續(xù)的任務(wù)。不過一般它會伴隨著進程池的關(guān)閉(close 函數(shù))才會使用。

apply_async 函數(shù)演示案例

接下里我們在 Pycharm 中創(chuàng)建一個腳本,練習(xí)一下關(guān)于進程池的使用方法。

  • 定義一個函數(shù),打印輸出該函數(shù) 每次被執(zhí)行的次數(shù) 與 該次數(shù)的進程號
  • 定義進程池的數(shù)量,每一次的執(zhí)行進程數(shù)量最多為該進程池設(shè)定的進程數(shù)

示例代碼如下:

# coding:utf-8


import os
import time
import multiprocessing

def work(count):    # 定義一個 work 函數(shù),打印輸出 每次執(zhí)行的次數(shù) 與 該次數(shù)的進程號
    print('\'work\' 函數(shù) 第 {} 次執(zhí)行,進程號為 {}'.format(count, os.getpid()))
    time.sleep(3)
    # print('********')


if __name__ == '__main__':
    pool = multiprocessing.Pool(3)      # 定義進程池的進程數(shù)量,同一時間每次執(zhí)行最多3個進程
    for i in range(21):
        pool.apply_async(func=work, args=(i,))      # 傳入的參數(shù)是元組,因為我們只有一個 i 參數(shù),所以我們要寫成 args=(i,)

    time.sleep(15)      # 這里的休眠時間是必須要加上的,否則我們的進程池還未運行,主進程就已經(jīng)運行結(jié)束,對應(yīng)的進程池也會關(guān)閉。

運行結(jié)果如下:

從上圖中我們可以看到每一次都是一次性運行三個進程,每一個進程的進程號是不一樣的,但仔細(xì)看會發(fā)現(xiàn)存在相同的進程號,這說明進程池的進程號在被重復(fù)利用。這證明我們上文介紹的內(nèi)容,進程池中的進程不會被關(guān)閉,可以反復(fù)使用。

而且我們還可以看到每隔3秒都會執(zhí)行3個進程,原因是我們的進程池中只有3個進程;雖然我們的 for 循環(huán) 中有 21 個任務(wù),work 函數(shù)會被執(zhí)行21次,但是由于我們的進程池中只有3個進程。所以當(dāng)執(zhí)行了3個任務(wù)之后(休眠3秒),后面的任務(wù)等待進程池中的進程處于空閑狀態(tài)之后才會繼續(xù)執(zhí)行。

同樣的,進程號在順序上回出現(xiàn)一定的區(qū)別,原因是因為我們使用的是一種 異步 的方法(異步即非同步)。這就導(dǎo)致 work 函數(shù) 一起執(zhí)行的三個任務(wù)會被打亂順序,這也是為什么我們的進程號出現(xiàn)順序不一致的原因。(更多的異步知識我們會在異步的章節(jié)進行詳細(xì)介紹)

進程池的原理: 上述腳本的案例證實了我們進程池關(guān)于進程的限制,只有當(dāng)我們進程池中的進程處于空閑狀態(tài)的時候才會將進程池外等待的任務(wù)扔到進程池中工作。

close 函數(shù)與 join 函數(shù) 演示

在上文的腳本中, 我們使用 time.sleep(15) 幫助我們將主進程阻塞15秒鐘再次退出,所以給了我們進程池足夠的時間完成我們的 work() 函數(shù)的循環(huán)任務(wù)。

如果沒有 time.sleep(15) 這句話又怎么辦呢,其實這里就可以使用進程的 join 函數(shù)了。不過上文我們也提到過,進程的 join() 函數(shù)一般都會伴隨進程池的關(guān)閉(close 函數(shù))來使用。接下來,我們就將上文腳本中的 time.sleep(15) 替換成 join() 函數(shù)試一下。

示例代碼如下:

# coding:utf-8


import os
import time
import multiprocessing

def work(count):    # 定義一個 work 函數(shù),打印輸出 每次執(zhí)行的次數(shù) 與 該次數(shù)的進程號
    print('\'work\' 函數(shù) 第 {} 次執(zhí)行,進程號為 {}'.format(count, os.getpid()))
    time.sleep(3)
    # print('********')


if __name__ == '__main__':
    pool = multiprocessing.Pool(3)      # 定義進程池的進程數(shù)量,同一時間每次執(zhí)行最多3個進程
    for i in range(21):
        pool.apply_async(func=work, args=(i,))      # 傳入的參數(shù)是元組,因為我們只有一個 i 參數(shù),所以我們要寫成 args=(i,)

    # time.sleep(15) 
    pool.close()
    pool.join()

運行結(jié)果如下:

從上面的動圖我們可以看出,work() 函數(shù)的任務(wù)與進程池中的進程與使用 time.sleep(15)的運行結(jié)果一致。

PS:如果我們的主進程會一直執(zhí)行,不會退出。那么我們并不需要添加 close() 與 join() 函數(shù) ,可以讓進程池一直啟動著,直到有任務(wù)進來就會執(zhí)行。

在后面學(xué)習(xí) WEB 開發(fā)之后,不退出主進程進行工作是家常便飯。還有一些需要長期執(zhí)行的任務(wù)也不會關(guān)閉,但要是只有一次性執(zhí)行的腳本,就需要添加 close() 與 join() 函數(shù) 來保證進程池的任務(wù)全部完成之后主進程再退出。當(dāng)然,如果主進程關(guān)閉了,就不會再接受新的任務(wù)了,也就代表了進程池的終結(jié)。

接下來再看一個例子,在 work 函數(shù) 中加入一個 return。

這里大家可能會有一個疑問,在上一章節(jié)針對進程的知識點明明說的是 進程無法獲取返回值,那么這里的 work() 函數(shù)增加的 return 又有什么意義呢?

其實不然,在我們的使用進程池的 apply_async 方法時,是通過異步的方式實現(xiàn)的,而異步是可以獲取返回值的。針對上述腳本,我們在 for循環(huán)中針對每一個異步 apply_async 添加一個變量名,從而獲取返回值。

示例代碼如下:

# coding:utf-8


import os
import time
import multiprocessing

def work(count):    # 定義一個 work 函數(shù),打印輸出 每次執(zhí)行的次數(shù) 與 該次數(shù)的進程號
    print('\'work\' 函數(shù) 第 {} 次執(zhí)行,進程號為 {}'.format(count, os.getpid()))
    time.sleep(3)
    return '\'work\' 函數(shù) result 返回值為:{}, 進程ID為:{}'.format(count, os.getpid())


if __name__ == '__main__':
    pool = multiprocessing.Pool(3)      # 定義進程池的進程數(shù)量,同一時間每次執(zhí)行最多3個進程
    results = []
    for i in range(21):
        result = pool.apply_async(func=work, args=(i,))      # 傳入的參數(shù)是元組,因為我們只有一個 i 參數(shù),所以我們要寫成 args=(i,)
        results.append(result)

    for result in results:
        print(result.get())     # 可以通過這個方式返回 apply_async 的返回值,
                                # 通過這種方式也不再需要 使用 close()、join() 函數(shù)就可以正常執(zhí)行。

    # time.sleep(15)      # 這里的休眠時間是必須要加上的,否則我們的進程池還未運行,主進程就已經(jīng)運行結(jié)束,對應(yīng)的進程池也會關(guān)閉。
    # pool.close()
    # pool.join()

運行結(jié)果如下:

從運行結(jié)果可以看出,首先 work() 函數(shù)被線程池的線程執(zhí)行了一遍,當(dāng)?shù)谝唤M任務(wù)執(zhí)行完畢緊接著執(zhí)行第二次線程池任務(wù)的時候,打印輸出了 apply_async 的返回值,證明返回值被成功的返回了。然后繼續(xù)下一組的任務(wù)…

這些都是主要依賴于 異步 ,關(guān)于 異步 的更多知識會在 異步 的章節(jié)進行詳細(xì)的介紹。

進程鎖

進程鎖的概念

鎖:大家都知道,我們可以給一個大門上鎖。

結(jié)合這個場景來舉一個例子:比如現(xiàn)在有多個進程同時沖向一個 "大門" ,當(dāng)前門內(nèi)是沒有 "人"的(其實就是進程),鎖也沒有鎖上。當(dāng)有一個進程進去之后并且把 “門” 鎖上了,這時候門外的那些進程是進不來的。在門內(nèi)的 “人” ,可以在 “門” 內(nèi)做任何事情且不會被干擾。當(dāng)它出來之后,會解開門鎖。這時候又有一個 “人” 進去了門內(nèi),并且重復(fù)這樣的操作,這就是 進程鎖。它可以讓鎖后面的工作只能被一個任務(wù)來處理,只有它解鎖之后下一個任務(wù)才會進入,這就是 “鎖” 的概念。

而 進程鎖 就是僅針對于 進程 有效的鎖,當(dāng)進程的任務(wù)開始之后,就會被上一把 “鎖”;與之對應(yīng)的是 線程鎖 ,它們的原理幾乎是一樣的。

進程鎖的加鎖與解鎖

進程鎖的使用方法:

通過 multiprocessing 導(dǎo)入 Manager 類

from multiprocessing import Manager

然后實例化 Manager

manager = Manager()

再然后通過實例化后的 manager 調(diào)用 它的 Lock() 函數(shù)

lock = manager.Lock()

接下來,就需要操作這個 lock 對象的函數(shù)

函數(shù)名介紹參數(shù)返回值
acquire上鎖
release解鎖(開鎖)

代碼示例如下:

# coding:utf-8


import os
import time
import multiprocessing


def work(count, lock):    # 定義一個 work 函數(shù),打印輸出 每次執(zhí)行的次數(shù) 與 該次數(shù)的進程號,增加線程鎖。
    lock.acquire()        # 上鎖
    print('\'work\' 函數(shù) 第 {} 次執(zhí)行,進程號為 {}'.format(count, os.getpid()))
    time.sleep(3)
    lock.release()        # 解鎖
    return '\'work\' 函數(shù) result 返回值為:{}, 進程ID為:{}'.format(count, os.getpid())


if __name__ == '__main__':
    pool = multiprocessing.Pool(3)      # 定義進程池的進程數(shù)量,同一時間每次執(zhí)行最多3個進程
    manager = multiprocessing.Manager()
    lock = manager.Lock()
    results = []
    for i in range(21):
        result = pool.apply_async(func=work, args=(i, lock))      # 傳入的參數(shù)是元組,因為我們只有一個 i 參數(shù),所以我們要寫成 args=(i,)
        # results.append(result)


    # time.sleep(15)      # 這里的休眠時間是必須要加上的,否則我們的進程池還未運行,主進程就已經(jīng)運行結(jié)束,對應(yīng)的進程池也會關(guān)閉。
    pool.close()
    pool.join()

執(zhí)行結(jié)果如下:

從上圖中,可以看到每一次只有一個任務(wù)會被執(zhí)行。由于每一個進程會被阻塞 3秒鐘,所以我們的進程執(zhí)行的非常慢。這是因為每一個進程進入到 work() 函數(shù)中,都會執(zhí)行 上鎖、阻塞3秒、解鎖 的過程,這樣就完成了一個進程的工作。下一個進程任務(wù)開始,重復(fù)這個過程… 這就是 進程鎖的概念。

其實進程鎖還有很多種方法,在 multiprocessing 中有一個直接使用的鎖,就是 ``from multiprocessing import Lock。這個Lock的鎖使用和我們剛剛介紹的Manager` 的鎖的使用有所區(qū)別。(這里不做詳細(xì)介紹,感興趣的話可以自行拓展一下。)

鎖 的使用可以讓我們對某個任務(wù) 在同一時間只能對一個進程進行開發(fā),但是 鎖也不可以亂用 。因為如果某些原因造成 鎖沒有正常解開 ,就會造成死鎖的現(xiàn)象,這樣就無法再進行操作了。

因為 鎖如果解不開 ,后面的任務(wù)也就沒有辦法繼續(xù)執(zhí)行任務(wù),所以使用鎖一定要謹(jǐn)慎。

OKK,今天我們學(xué)習(xí)了進程池與鎖的使用方法,通過學(xué)習(xí)這兩個知識點可以幫助我們解決進程的一些弊端,但它們自身的使用也要注意一些事項。在不同的場景使用的效果也不盡相同,而 鎖的使用 則更需要注意。

以上就是Python語法學(xué)習(xí)之進程池與進程鎖詳解的詳細(xì)內(nèi)容,更多關(guān)于Python進程池 進程鎖的資料請關(guān)注腳本之家其它相關(guān)文章! 

相關(guān)文章

  • Python 中將值附加到集合的操作方法

    Python 中將值附加到集合的操作方法

    這篇文章主要介紹了Python 中將值附加到集合的操作方法,通過使用 add() 方法或 update() 方法,你可以向 Python 中的集合中添加元素,在添加元素時,需要注意不允許重復(fù)元素和集合是無序的,本文通過示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-05-05
  • python3 面向?qū)ο骭_類的內(nèi)置屬性與方法的實例代碼

    python3 面向?qū)ο骭_類的內(nèi)置屬性與方法的實例代碼

    這篇文章主要介紹了python3 面向?qū)ο骭_類的內(nèi)置屬性與方法的實例代碼,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-11-11
  • Pycharm設(shè)置utf-8自動顯示方法

    Pycharm設(shè)置utf-8自動顯示方法

    今天小編就為大家分享一篇Pycharm設(shè)置utf-8自動顯示方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-01-01
  • Python定時執(zhí)行之Timer用法示例

    Python定時執(zhí)行之Timer用法示例

    這篇文章主要介紹了Python定時執(zhí)行之Timer用法,實例分析了Timer模塊的原理及相關(guān)使用技巧,需要的朋友可以參考下
    2015-05-05
  • 基于Python開發(fā)云主機類型管理腳本分享

    基于Python開發(fā)云主機類型管理腳本分享

    這篇文章主要為大家詳細(xì)介紹了如何基于Python開發(fā)一個云主機類型管理腳本,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-02-02
  • python 合并列表的八種方法

    python 合并列表的八種方法

    這篇文章主要介紹了python 連接列表的八種方法,幫助大家更好的理解和學(xué)習(xí)使用python,感興趣的朋友可以了解下
    2021-03-03
  • 關(guān)于python的縮進規(guī)則的知識點詳解

    關(guān)于python的縮進規(guī)則的知識點詳解

    在本篇文章里小編給大家整理了關(guān)于python的縮進規(guī)則的知識點詳解,有興趣的朋友們可以學(xué)習(xí)下。
    2020-06-06
  • python中模塊導(dǎo)入模式詳解

    python中模塊導(dǎo)入模式詳解

    這篇文章主要為大家介紹了python中模塊導(dǎo)入的模式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-07-07
  • pandas series序列轉(zhuǎn)化為星期幾的實例

    pandas series序列轉(zhuǎn)化為星期幾的實例

    下面小編就為大家分享一篇pandas series序列轉(zhuǎn)化為星期幾的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-04-04
  • Python刪除指定目錄下過期文件的2個腳本分享

    Python刪除指定目錄下過期文件的2個腳本分享

    這篇文章主要介紹了Python刪除指定目錄下過期文件2個腳本分享,可以用在如刪除指定日期前的日志文件,需要的朋友可以參考下
    2014-04-04

最新評論