亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Python進程池與進程鎖實例分析

發布時間:2022-04-11 10:55:11 來源:億速云 閱讀:99 作者:iii 欄目:開發技術

本篇內容主要講解“Python進程池與進程鎖實例分析”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Python進程池與進程鎖實例分析”吧!

進程池

什么是進程池

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

我們可以認為進程池就是一個池子,在這個池子里提前創建好一定數量的進程。見下圖:

Python進程池與進程鎖實例分析

比如這個紅色矩形陣列就代表一個進程池子,在這個池子中有6個進程。這6個進程會伴隨進程池一起被創建,不僅如此,我們在學習面向對象的生命周期的時候曾經說過,每個實例化對象在使用完成之后都會被內存管家回收。

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

當然,當我們執行完程序進程池關閉的時候,進程也隨之關閉。

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

這就是進程池的作用。

進程池的創建模塊 - multiprocessing

創建進程池函數 - Pool

函數名介紹參數返回值
Pool進程池的創建Processcount進程池對象

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

進程池的常用方法

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

函數名介紹參數返回值
apply_async任務加入進程池(異步)func,args
close關閉進程池
join等待進程池任務結束
  • apply_async 函數:它的功能是將任務加入到進程池中,并且是通過異步實現的。異步 這個知識我們還沒有學習,先不用關心它到底是什么意思。它有兩個參數:func 與 agrs , func 是加入進程池中工作的函數;args 是一個元組,代表著簽一個函數的參數,這和我們創建并使用一個進程是完全一致的。

  • close 函數:當我們使用完進程池之后,通過調用 close 函數可以關閉進程池。它沒有任何的參數,也沒有任何的返回值。

  • join 函數:它和我們上一章節學習的 創建進程的 join 函數中方法是一致的。只有進程池中的任務全部執行完畢之后,才會執行后續的任務。不過一般它會伴隨著進程池的關閉(close 函數)才會使用。

apply_async 函數演示案例

接下里我們在 Pycharm 中創建一個腳本,練習一下關于進程池的使用方法。

  • 定義一個函數,打印輸出該函數 每次被執行的次數 與 該次數的進程號

  • 定義進程池的數量,每一次的執行進程數量最多為該進程池設定的進程數

示例代碼如下:

# coding:utf-8


import os
import time
import multiprocessing

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


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

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

運行結果如下:

Python進程池與進程鎖實例分析

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

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

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

進程池的原理: 上述腳本的案例證實了我們進程池關于進程的限制,只有當我們進程池中的進程處于空閑狀態的時候才會將進程池外等待的任務扔到進程池中工作。

close 函數與 join 函數 演示

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

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

示例代碼如下:

# coding:utf-8


import os
import time
import multiprocessing

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


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

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

運行結果如下:

Python進程池與進程鎖實例分析

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

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

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

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

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

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

示例代碼如下:

# coding:utf-8


import os
import time
import multiprocessing

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


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

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

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

運行結果如下:

Python進程池與進程鎖實例分析

從運行結果可以看出,首先 work() 函數被線程池的線程執行了一遍,當第一組任務執行完畢緊接著執行第二次線程池任務的時候,打印輸出了 apply_async 的返回值,證明返回值被成功的返回了。然后繼續下一組的任務…

這些都是主要依賴于 異步 ,關于 異步 的更多知識會在 異步 的章節進行詳細的介紹。

進程鎖

進程鎖的概念

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

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

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

進程鎖的加鎖與解鎖

進程鎖的使用方法:

通過 multiprocessing 導入 Manager 類

from multiprocessing import Manager

然后實例化 Manager

manager = Manager()

再然后通過實例化后的 manager 調用 它的 Lock() 函數

lock = manager.Lock()

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

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

代碼示例如下:

# coding:utf-8


import os
import time
import multiprocessing


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


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


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

執行結果如下:

Python進程池與進程鎖實例分析

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

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

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

因為 鎖如果解不開 ,后面的任務也就沒有辦法繼續執行任務,所以使用鎖一定要謹慎。

 

到此,相信大家對“Python進程池與進程鎖實例分析”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

吴川市| 奎屯市| 彭山县| 广丰县| 宁夏| 宜黄县| 临泉县| 威宁| 桂阳县| 广灵县| 林芝县| 望奎县| 延庆县| 长宁区| 翁源县| 合阳县| 鄱阳县| 兴国县| 黎川县| 双牌县| 博白县| 泸定县| 汶川县| 营山县| 仁怀市| 新邵县| 桐城市| 池州市| 无极县| 凤山市| 扶沟县| 柳林县| 霍城县| 铜陵市| 巧家县| 镶黄旗| 昭通市| 滦平县| 华安县| 天柱县| 静海县|