python高階(二) 多工(三)協程(2)

2021-09-03 07:01:19 字數 4566 閱讀 4265

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

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

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

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

import time

def work1():

while true:

print("----work1---")

yield

time.sleep(0.5)

def work2():

while true:

print("----work2---")

yield

time.sleep(0.5)

def main():

w1 = work1()

w2 = work2()

while true:

next(w1)

next(w2)

if __name__ == "__main__":

main()

執行結果:

----work1---

----work2---

----work1---

----work2---

----work1---

----work2---

----work1---

----work2---

----work1---

----work2---

----work1---

----work2---

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

使用如下命令安裝greenlet模組:

sudo pip3 install greenlet
#coding=utf-8

from greenlet import greenlet

import time

def test1():

while true:

print "---a--"

gr2.switch()

time.sleep(0.5)

def test2():

while true:

print "---b--"

gr1.switch()

time.sleep(0.5)

gr1 = greenlet(test1)

gr2 = greenlet(test2)

#切換到gr1中執行

gr1.switch()

---a--

---b--

---a--

---b--

---a--

---b--

---a--

---b--

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

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

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

pip3 install gevent
import gevent

def f(n):

for i in range(n):

print(gevent.getcurrent(), i)

g1 = gevent.spawn(f, 5)

g2 = gevent.spawn(f, 5)

g3 = gevent.spawn(f, 5)

g1.join()

g2.join()

g3.join()

執行結果

012

3401

2340

1234

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

import gevent

def f(n):

for i in range(n):

print(gevent.getcurrent(), i)

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

gevent.sleep(1)

g1 = gevent.spawn(f, 5)

g2 = gevent.spawn(f, 5)

g3 = gevent.spawn(f, 5)

g1.join()

g2.join()

g3.join()

執行結果

000

1112

2233

3444

from gevent import monkey

import gevent

import random

import time

def coroutine_work(coroutine_name):

for i in range(10):

print(coroutine_name, i)

time.sleep(random.random())

gevent.joinall([

gevent.spawn(coroutine_work, "work1"),

gevent.spawn(coroutine_work, "work2")

])

執行結果

work1 0

work1 1

work1 2

work1 3

work1 4

work1 5

work1 6

work1 7

work1 8

work1 9

work2 0

work2 1

work2 2

work2 3

work2 4

work2 5

work2 6

work2 7

work2 8

work2 9

from gevent import monkey

import gevent

import random

import time

# 有耗時操作時需要

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

def coroutine_work(coroutine_name):

for i in range(10):

print(coroutine_name, i)

time.sleep(random.random())

gevent.joinall([

gevent.spawn(coroutine_work, "work1"),

gevent.spawn(coroutine_work, "work2")

])

執行結果

work1 0

work2 0

work1 1

work1 2

work1 3

work2 1

work1 4

work2 2

work1 5

work2 3

work1 6

work1 7

work1 8

work2 4

work2 5

work1 9

work2 6

work2 7

work2 8

work2 9

請仔細理解如下的通俗描述

簡單總結

程序是資源分配的單位

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

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

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

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

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

python高階程式設計語法 多工 協程(三)

在開始介紹協程之前,咱們先了解一下迭代器和生成器,因為要學習協程,這兩部分更是關鍵。迭代 是訪問集合元素的一種方法,迭代器是乙個可以記住遍歷的位置的物件。迭代器物件從集合的第乙個元素開始訪問,直到所有的元素被訪問完結束,迭代器只能往前不能後退。我們可以對list,tuple,str等型別的資料使用f...

Python 多工 協程

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

多工 協程

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