Python基礎學習之多工 協程詳細講解

2021-09-18 01:27:39 字數 4711 閱讀 8641

前言

學習python的小夥伴對於他的多工一定不會陌生,那麼多工中的協程又有幾個小夥伴們知道呢?在本文將重點剖析協程這個知識點。

正文

一、協程簡介

協程協程,又稱微執行緒,纖程。英文名coroutine。

協程是python個中另外一種實現多工的方式,只不過比執行緒更小占用更小執行單元(理解為需要的資源)。 為啥說它是乙個執行單元,因為它自帶cpu上下文。這樣只要在合適的時機, 我們可以把乙個協程 切換到另乙個協程。 只要這個過程中儲存或恢復 cpu上下文那麼程式還是可以執行的。

通俗的理解:在乙個執行緒中的某個函式,可以在任何地方儲存當前函式的一些臨時變數等資訊,然後切換到另外乙個函式中執行,注意不是通過呼叫函式的方式做到的,並且切換的次數以及什麼時候再切換到原來的函式都由開發者自己確定

協程和執行緒差異

在實現多工時, 執行緒切換從系統層面遠不止儲存和恢復 cpu上下文這麼簡單。 作業系統為了程式執行的高效性每個執行緒都有自己快取cache等等資料,作業系統還會幫你做這些資料的恢復操作。 所以執行緒的切換非常耗效能。但是協程的切換只是單純的操作cpu的上下文,所以一秒鐘切換個上百萬次系統都抗的住。

# 程序 啟動多個程序 程序之間是由作業系統負責呼叫

# 執行緒 啟動多個執行緒 真正被cpu執行的最小單位實際是執行緒

# 協程

# 本質上是乙個執行緒

# 能夠在多個任務之間切換來節省一些io時間

# 協程中任務之間的切換也消耗時間,但是開銷要遠遠小於程序執行緒之間的切換

簡單實現協程

import time

def work1():

while true:

print(「work1」)

yield

time.sleep(0.5)

def work2():

while true:

print(「work2」)

yield

time.sleep(0.5)

ifname== 「main」:

w1 = work1()

w2 = work2()

while true:

next(w1)

next(w2)

二、greenlet

為了更好使用協程來完成多工,python中的greenlet模組對其封裝,從而使得切換任務變的更加簡單。

from greenlet import greenlet

import time

def test1():

while true:

print(「test1」)

# 切換gt2執行

gt2.switch()

time.sleep(1)

def test2():

while true:

print(「test2」)

# 切換gt1執行

gt1.switch()

time.sleep(1)

gt1 = greenlet(test1)

gt2 = greenlet(test2)

gt1.switch()

三、gevent

greenlet已經實現了協程,但是這個還得人工切換,是不是覺得太麻煩了,不要捉急,python還有乙個比greenlet更強大的並且能夠自動切換任務的模組gevent

其原理是當乙個greenlet遇到io(指的是input output 輸入輸出,比如網路、檔案操作等)操作時,比如訪問網路,就自動切換到其他的greenlet,等到io操作完成,再在適當的時候切換回來繼續執行。

由於io操作非常耗時,經常使程式處於等待狀態,有了gevent為我們自動切換協程,就保證總有greenlet在執行,而不是等待io。

1、gevent的使用

import gevent

def test(n):

for i in range(n):

print(gevent.getcurrent(), i)

g1 = gevent.spawn(test, 5)

g2 = gevent.spawn(test, 5)

g3 = gevent.spawn(test, 5)

g1.join()

g2.join()

g3.join()01

2340

1234

0123

4可以看到,3個greenlet是依次執行而不是交替執行

2. gevent切換執行

import gevent

def test(n):

for i in range(n):

print(gevent.getcurrent(), i)

gevent.sleep(1) # 用來模擬乙個耗時操作,注意不是time模組中的sleep

g1 = gevent.spawn(test, 5)

g2 = gevent.spawn(test, 5)

g3 = gevent.spawn(test, 5)

g1.join()

g2.join()

g3.join()00

0111

2223

3344

43. 給程式打補丁

import gevent

from gevent import monkey

import random

import time

monkey.patch_all() # 將程式中用到的耗時操作的**,換為gevent中自己實現的模組

def test(name):

for i in range(10):

print(name, i)

time.sleep(random.random())

gevent.joinall([

gevent.spawn(test, 「test1」),

gevent.spawn(test, 「test2」)

])test1 0

test2 0

test2 1

test1 1

test1 2

test1 3

test2 2

test1 4

test1 5

test2 3

test1 6

test1 7

test2 4

test2 5

test1 8

test2 6

test2 7

test1 9

test2 8

test2 9

四、程序、執行緒、協程對比

通俗描述

有乙個老闆想要開個工廠進行生產某件商品(例如剪子)

他需要花一些財力物力製作一條生產線,這個生產線上有很多的器件以及材料這些所有的 為了能夠生產剪子而準備的資源稱之為:程序

只有生產線是不能夠進行生產的,所以老闆的找個工人來進行生產,這個工人能夠利用這些材料最終一步步的將剪子做出來,這個來做事情的工人稱之為:執行緒

這個老闆為了提高生產率,想到3種辦法:

在這條生產線上多招些工人,一起來做剪子,這樣效率是成倍増長,即單程序 多執行緒方式

老闆發現這條生產線上的工人不是越多越好,因為一條生產線的資源以及材料畢竟有限,所以老闆又花了些財力物力購置了另外一條生產線,然後再招些工人這樣效率又再一步提高了,即多程序 多執行緒方式

老闆發現,現在已經有了很多條生產線,並且每條生產線上已經有很多任務人了(即程式是多程序的,每個程序中又有多個執行緒),為了再次提高效率,老闆想了個損招,規定:如果某個員工在上班時臨時沒事或者再等待某些條件(比如等待另乙個工人生產完謀道工序 之後他才能再次工作) ,那麼這個員工就利用這個時間去做其它的事情,那麼也就是說:如果乙個執行緒等待某些條件,可以充分利用這個時間去做其它事情,其實這就是:協程方式

簡單總結

程序是資源分配的單位

執行緒是作業系統排程的單位

程序切換需要的資源很最大,效率很低

執行緒切換需要的資源一般,效率一般(當然了在不考慮gil的情況下)

協程切換任務資源很小,效率高

多程序、多執行緒根據cpu核數不一樣可能是並行的,但是協程是在乙個執行緒中 所以是併發

])結論

通過本文的的**例項講解各位小夥伴們對於python開發多工中的協程是不是有了乙個初步的了解?那麼接下來就靠小夥伴們自己的多多努力了。

Python 多工 協程

高階程式設計技巧 學習筆記 1.1 同步 非同步 1.2 阻塞 非阻塞 2.1 什麼是協程?協程,又稱微執行緒。協程是 python 個中另外一種實現多工的方式,只不過比執行緒更小占用更小執行單元 理解為需要的資源 2.2 python中的協程大概經歷了如下三個階段 最初的生成器變形yield se...

Python 多工之協程(3)實現多工

學習理解迭代器和生成器之後,開始使用協程來實現多工 當乙個函式中包含yield關鍵字,那麼這個函式就不再是乙個普通的函式,它的返回值是乙個生成器物件。我們可以使用next 或send 函式來啟動喚醒生成器物件,當程式第一次執行到yield時,程式暫停執行,並返回yield後邊跟的變數,當再次喚醒時,...

多工 協程

示例 import time defwork1 while true print 正在掃地 yield defwork2 while true print 正在搬磚 yield w1 work1 w2 work2 協程肯定是併發執行 while true next w1 next w2 greenl...