App下載

如何提高python效率?——并發(fā)編程介紹

w3cschool小編 2022-12-19 15:55:19 瀏覽數(shù) (2549)
反饋

對于計算機而言,提高效率的方式其實是比較有限的,因為除非從底層代碼(匯編代碼)進行優(yōu)化,否則想要提升效率是比較困難的,只能通過不斷的優(yōu)化代碼和算法,提高效率。但實際上還有另外的方法也可以提高效率,來看看python有哪些提高效率的方法:

基礎概念介紹

進程:進程是一個程序的執(zhí)行實例,他是一個動態(tài)的概念,是操作系統(tǒng)進行資源分配的基本(最?。﹩挝唬粋€進程中包含了程序執(zhí)行過程中的所有資源。進程之間數(shù)據(jù)交換需要使用到中間件。

線程:線程是CPU的最小調(diào)度單位,同一個進程里面的線程共享所有資源(沒錯,一個進程里可以有多個線程,每個線程都運行在同一進程的上下文中,共享同樣的代碼和全局數(shù)據(jù),所以線程間的數(shù)據(jù)交換會來得容易些)。

協(xié)程:由于python存在GIL鎖,似的python的多線程沒有太多意義,這時候出現(xiàn)了自己操作線程的切換,以降低線程切換的開銷,這就是協(xié)程。

 通俗理解線程進程的關系:

進程是連鎖店,線程是店里的灶臺

一個進程可以有多個線程,——》一個連鎖店可以有多個灶臺

進程間不能直接通信——》連鎖店之間通信是不方便的

線程間共享所有支援,可以直接通信——》灶臺之間共享店內(nèi)的所有食材
進程要比線程消耗更多的計算機資源?!烽_個店比開個灶臺更貴

提升效率的方法一——多進程

在上文的類比中,我們可以知道進程是連鎖店,為了賺大錢(提高效率),我們可以多開幾家店,這就是多進程技術。

在python中多進程使用multiprocessing庫來實現(xiàn)。示例如下所示:

# import 多進程庫
import multiprocessing

def worker1(name):
    print("worker1 name is " + name)

def worker2(name):
    print('worker2 name is' + name )


if __name__ == "__main__":
    # target后面?zhèn)魅胍噙M程的方法,args以元組的方式傳入?yún)?shù)
    # 創(chuàng)建兩個進程分別調(diào)用不同的方法
    p1 = multiprocessing.Process(target=worker1, args=('subprocess1',)) 
    p2 = multiprocessing.Process(target=worker2, args=('subprocess2'))

    #啟動進程
    p1.start()
    p2.start()
    
    #停止進程
    p1.join()  
    p2.join()

還記得上文提到的嘛?多進程間進程通信是比較困難的,但這并不代表沒有通信的手段,為了實現(xiàn)多進程間的通信,我們可以使用隊列(Queue)來實現(xiàn),它是一種多進程安全的隊列,有關他的更多用法可以查看python3教程中的相關文檔。

 為什么要使用隊列來進行通信?很簡單,因為如果沒有通信,進程之間就無法協(xié)作,會出現(xiàn)沖突,就像開連鎖店一樣,如果沒有協(xié)調(diào)好每個店的經(jīng)營內(nèi)容,可能會出現(xiàn)互相搶客戶的現(xiàn)象。

提升效率的方法二——多線程

多線程技術在其他語言中是可以正常使用的,但在python中有例外,因為python存在一個GIL鎖,它規(guī)定了線程在運行時,需要先拿到通行證,否則就不能運行,也就意味著一個python的進程里,無論你有多少個線程,永遠只能單線程運行。

還記得上文說過,線程是cpu最小調(diào)度單位嗎?也就意味著,python多線程是無法使用多核的,但是多進程是可以利用多核的。

 怎么理解GIL鎖呢,其實就是相當于只有一個大師傅,雖然你有很多灶臺,但是你只有一個人可以做菜。

那么python的多線程是不是沒用呢?不是,如果你的程序是CPU密集型的,那么python的多線程是完全沒有意義,甚至由于線程切換的花銷,會導致更慢點。

但如果你的是IO密集型,那么多線程的提升還是很明顯的。

 io密集型,就是讀取數(shù)據(jù)比較耗費時間,而cpu處理時間比較短,程序花費的空閑的時間主要是cpu在等待io,這就是io密集型,比如等待網(wǎng)絡數(shù)據(jù),文件讀寫等

CPU密集型,就是處理數(shù)據(jù)比較耗費時間,讀寫不耗費時間,程序花費的時間主要是cpu在處理數(shù)據(jù),而只有一小段時間是用在io上,這就是cpu密集型,比如算法運算,復雜邏輯處理等等。

以大師傅為例,io密集型說的就是食材的烹飪前處理、端菜上桌比較耗費時間,cpu密集型說的就是食材做成才比較耗費時間。

雖然大師傅可以有很多個灶臺,但大師傅只有一個,cpu密集型的程序就相當于大師傅要一直做菜,還要從一個灶臺跑到另一個灶臺,大師傅會很累,而且同一時間內(nèi)大師傅只能在一個灶臺上做菜,所以實際上也沒有更快,因為大師傅還要跑來跑去,反而更慢了
io密集型的程序就相當于大師傅做刺身(很簡單的料理,但是提前處理材料很麻煩),每個灶臺都有自動處理機器,它可以自動把食材處理好,只要大師傅到位就可以做菜,做完也可以不用管,馬上切換到別的灶臺繼續(xù)做。所以多線程對于io密集型的程序提升確實是比較明顯的。

python的多線程使用的是threading庫(其實還有thread庫,但這個庫比較簡單,不推薦),示例如下所示:

# import 線程庫
import threading

# 這個函數(shù)名可隨便定義
def run(n):
    print("current task:", n)

if __name__ == "__main__":
    # 創(chuàng)建線程
    t1 = threading.Thread(target=run, args=("thread 1",))
    t2 = threading.Thread(target=run, args=("thread 2",))
    t1.start()
    t2.start()

協(xié)程介紹

協(xié)程是一種操作,原來多線程是由CPU控制的,而協(xié)程則是自己控制。當代碼中出現(xiàn)有io處理的時候,先代碼自行調(diào)度,將這個操作掛起,然后去繼續(xù)執(zhí)行其他操作。

這樣的話,cpu就不會因為代碼中出現(xiàn)io處理進行線程切換,從而減少線程切換的花銷,提升運行速度。

 大師傅在做菜的時候可能需要蒸十五分鐘,這十五分鐘大師傅完全可以去干別的,按照原來的多線程,大師傅得把這個灶頭的菜坐完再切換到別的灶頭,而協(xié)程的出現(xiàn)則改變了這個情況,大師傅發(fā)現(xiàn)蒸菜十五分鐘,他就去別的灶臺干別的活了,等到蒸好了再切換回來。

python的協(xié)程使用的asyncio庫,示例代碼如下所示:

import asyncio
 # 需要利用隊列來進行協(xié)程之間的數(shù)據(jù)交換
queue =  asyncio.Queue()

async def Producer():
        n = 0
        while True:
            await asyncio.sleep(2)
            print('add value to queue:',str(n))
            await queue.put(n)
            n = n + 1

async def Consumer():
    while True:
        try:
            r = await  asyncio.wait_for(queue.get(), timeout=1.0)
            print('consumer value>>>>>>>>>>>>>>>>>>', r)
        except asyncio.TimeoutError:
            print('get value timeout')
            continue
        except:
            break
    print('quit')
loop = asyncio.get_event_loop()
tasks = [Producer(), Consumer()]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

協(xié)程跟進程、線程的區(qū)別

  1. 協(xié)程既不是進程也不是線程,協(xié)程僅僅是一個特殊的函數(shù),協(xié)程它進程和進程不是一個維度的。
  2. 一個進程可以包含多個線程,一個線程可以包含多個協(xié)程。
  3. 一個線程內(nèi)的多個協(xié)程雖然可以切換,但是多個協(xié)程是串行執(zhí)行的,只能在一個線程內(nèi)運行,沒法利用CPU多核能力。
  4. 協(xié)程與進程一樣,切換是存在上下文切換問題的。

小結(jié)

以上就是有關于python并發(fā)編程的簡單介紹了,想要更多了解python的并發(fā)編程,可以前往裴帥帥老師的新課程——Python 多線程多進程多協(xié)程 并發(fā)編程實戰(zhàn)進行學習!

Python 多線程多進程多協(xié)程 并發(fā)編程實戰(zhàn)

2 人點贊