[Python 多線程] multiprocessing、多進程、工作進程池 (十四)


 

由於Python的GIL限制,多線程未必是CPU密集型程序的好的選擇。

多進程可以完全獨立的進程環境中運行程序,可以充分地利用多處理器。

但是進程本身的隔離性帶來的數據不共享也是一個問題。而且線程比進程輕量級。

 

multiprocessing

Process類

Process類遵循了Thread類的API,減少了學習難度。(幾乎和Thread類使用方法一模一樣) 

 

 

 

上一篇文章里最后使用了多線程來解決CPU密集型的例子,但發現多線程和多線程最終執行效率幾乎相同,多線程並沒有想象中的優勢。

上一篇中多線程的例子:

#模擬CPU密集型 多線程
import threading,logging,time,random,datetime
DATEFMT="%H:%M:%S"
FORMAT = "[%(asctime)s]\t [%(threadName)s,%(thread)d] %(message)s"
logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt=DATEFMT)


def calc():
    sum = 0
    for _ in range(100000000):
        sum += 1

start =datetime.datetime.now()

t1 = threading.Thread(target=calc)
t2 = threading.Thread(target=calc)
t3 = threading.Thread(target=calc)
t4 = threading.Thread(target=calc)
t5 = threading.Thread(target=calc)

t1.start()
t2.start()
t3.start()
t4.start()
t5.start()

t1.join()
t2.join()
t3.join()
t4.join()
t5.join()


print('aaa')
delta = (datetime.datetime.now() -start).total_seconds()
print(delta)

#運行結果:
aaa
53.135543

  此例子是單線程情況下執行耗時58秒左右。

再使用多進程的例子來看一下是否可以有所不同:

#=========多進程、真正的並行、適用於CPU計算密集型===============
import multiprocessing
import datetime

def calc(i):
    sum = 0
    for _ in range(100000000):
        sum += 1
        # print(i,sum)

if __name__ == "__main__":
    start = datetime.datetime.now()
    lst = []

    for i in range(5):
        p = multiprocessing.Process(target=calc,args=(i,),name='p-{}'.format(i))
        p.start()
        lst.append(p)

    for p in lst:
        p.join()

    delta = (datetime.datetime.now() - start).total_seconds()
    print(delta)

運行結果:
24.767709

  從耗時結果可以看出多線程的執行效率明顯得要比多線程(其實就是單線程)高得多。

 

進程間同步:

 進程間同步提供了和線程同步一樣的類,使用方法一樣,使用的效果也類似。

不過,進程間代價要高於線程,而且底層😡實現是不同的,只不過Python屏蔽了這些,讓用戶簡單使用。

 

multiprocessing還提供共享內存、服務器進程來共享數據,還提供了Queue隊列、Pipe管道用於進程間通信。

 

通信方式不同:

多線程就是啟動多個解釋器進程,進程間通信必須序列化、反序列化

數據的線程安全性問題

  由於每個進程中沒有實現多線程,GIL可以說沒什么用了。

 

進程池舉例:

進程池只能由創建它的進程使用

# 進程池

import multiprocessing
import datetime

def calc(i):
    sum = 0
    for _ in range(100000000):
        sum += 1

if __name__ == "__main__":
    start = datetime.datetime.now()

    pool = multiprocessing.Pool(5) #定義同時至多起幾個線程
    for i in range(5):
        pool.apply_async(calc,args=(i,))

    pool.close()
    pool.join()

    #多線程
    # lst = []

    # for i in range(5):
    #     p = multiprocessing.Process(target=calc,args=(i,),name='p-{}'.format(i))
    #     p.start()
    #     lst.append(p)
    #
    # for p in lst:
    #     p.join()

    delta = (datetime.datetime.now() - start).total_seconds()
    print(delta)

運行結果:
24.944169

  

 

多進程、多線程的選擇

1、CPU密集型

CPython中使用到了GIL,多線程的時候鎖相互競爭,且多核優勢不能發揮,Python多進程效率更高。

2、IO密集型

適合是用多線程,減少IO序列化開銷。且在IO等待的時候,切換到其它線程繼續執行,效率不錯。

 

應用:

請求/應答模型:WEB應用中常見的處理模型

 

master啟動多個worker工作進程,一般和CPU數目相同。

worker工作進程中啟動多線程,提高並發處理能力。worker處理用戶的請求,往往需要等待數據。

這就是nginx工作模式。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM