成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

python---協(xié)程

lolomaco / 2586人閱讀

摘要:隨著我們對(duì)于效率的追求不斷提高,基于單線程來(lái)實(shí)現(xiàn)并發(fā)又成為一個(gè)新的課題,即只用一個(gè)主線程很明顯可利用的只有一個(gè)情況下實(shí)現(xiàn)并發(fā)。作為的補(bǔ)充可以檢測(cè)操作,在遇到操作的情況下才發(fā)生切換協(xié)程介紹協(xié)程是單線程下的并發(fā),又稱(chēng)微線程,纖程。

引子

之前我們學(xué)習(xí)了線程、進(jìn)程的概念,了解了在操作系統(tǒng)中進(jìn)程是資源分配的最小單位,線程是CPU調(diào)度的最小單位。按道理來(lái)說(shuō)我們已經(jīng)算是把cpu的利用率提高很多了。但是我們知道無(wú)論是創(chuàng)建多進(jìn)程還是創(chuàng)建多線程來(lái)解決問(wèn)題,都要消耗一定的時(shí)間來(lái)創(chuàng)建進(jìn)程、創(chuàng)建線程、以及管理他們之間的切換。
  隨著我們對(duì)于效率的追求不斷提高,基于單線程來(lái)實(shí)現(xiàn)并發(fā)又成為一個(gè)新的課題,即只用一個(gè)主線程(很明顯可利用的cpu只有一個(gè))情況下實(shí)現(xiàn)并發(fā)。這樣就可以節(jié)省創(chuàng)建線進(jìn)程所消耗的時(shí)間。
  為此我們需要先回顧下并發(fā)的本質(zhì):切換+保存狀態(tài)
  cpu正在運(yùn)行一個(gè)任務(wù),會(huì)在兩種情況下切走去執(zhí)行其他的任務(wù)(切換由操作系統(tǒng)強(qiáng)制控制),一種情況是該任務(wù)發(fā)生了阻塞,另外一種情況是該任務(wù)計(jì)算的時(shí)間過(guò)長(zhǎng)

在介紹進(jìn)程理論時(shí),提及進(jìn)程的三種執(zhí)行狀態(tài),而線程才是執(zhí)行單位,所以也可以將上圖理解為線程的三種狀態(tài)
一:其中第二種情況并不能提升效率,只是為了讓cpu能夠雨露均沾,實(shí)現(xiàn)看起來(lái)所有任務(wù)都被“同時(shí)”執(zhí)行的效果,如果多個(gè)任務(wù)都是純計(jì)算的,這種切換反而會(huì)降低效率。
  為此我們可以基于yield來(lái)驗(yàn)證。yield本身就是一種在單線程下可以保存任務(wù)運(yùn)行狀態(tài)的方法:

1 yiled可以保存狀態(tài),yield的狀態(tài)保存與操作系統(tǒng)的保存線程狀態(tài)很像,但是yield是代碼級(jí)別控制的,更輕量級(jí)
2 send可以把一個(gè)函數(shù)的結(jié)果傳給另外一個(gè)函數(shù),以此實(shí)現(xiàn)單線程內(nèi)程序之間的切換
#串行執(zhí)行
import time
def consumer(res):
    """任務(wù)1:接收數(shù)據(jù),處理數(shù)據(jù)"""
    pass

def producer():
    """任務(wù)2:生產(chǎn)數(shù)據(jù)"""
    res=[]
    for i in range(10000000):
        res.append(i)
    return res

start=time.time()
#串行執(zhí)行
res=producer()
consumer(res) #寫(xiě)成consumer(producer())會(huì)降低執(zhí)行效率
stop=time.time()
print(stop-start) #1.874000072479248


#基于yield并發(fā)執(zhí)行
import time
def consumer():
    """任務(wù)1:接收數(shù)據(jù),處理數(shù)據(jù)"""
    while True:
        print("this is consumer")
        x=yield

def producer():
    """任務(wù)2:生產(chǎn)數(shù)據(jù)"""
    g=consumer()
    next(g)
    for i in range(10):
        print("this is prodecer")
        g.send(i)

start=time.time()
#基于yield保存狀態(tài),實(shí)現(xiàn)兩個(gè)任務(wù)直接來(lái)回切換,即并發(fā)的效果
#PS:如果每個(gè)任務(wù)中都加上打印,那么明顯地看到兩個(gè)任務(wù)的打印是你一次我一次,即并發(fā)執(zhí)行的.
producer()

stop=time.time()
print(stop-start) #2.0272178649902344

二:第一種情況的切換。在任務(wù)一遇到io情況下,切到任務(wù)二去執(zhí)行,這樣就可以利用任務(wù)一阻塞的時(shí)間完成任務(wù)二的計(jì)算,效率的提升就在于此。

import time
def consumer():
    """任務(wù)1:接收數(shù)據(jù),處理數(shù)據(jù)"""
    while True:
        x=yield

def producer():
    """任務(wù)2:生產(chǎn)數(shù)據(jù)"""
    g=consumer()
    next(g)
    for i in range(10000000):
        g.send(i)
        time.sleep(2)

start=time.time()
producer() #并發(fā)執(zhí)行,但是任務(wù)producer遇到io就會(huì)阻塞住,并不會(huì)切到該線程內(nèi)的其他任務(wù)去執(zhí)行

stop=time.time()
print(stop-start)

對(duì)于單線程下,我們不可避免程序中出現(xiàn)io操作,但如果我們能在自己的程序中(即用戶程序級(jí)別,而非操作系統(tǒng)級(jí)別)控制單線程下的多個(gè)任務(wù)能在一個(gè)任務(wù)遇到io阻塞時(shí)就切換到另外一個(gè)任務(wù)去計(jì)算,這樣就保證了該線程能夠最大限度地處于就緒態(tài),即隨時(shí)都可以被cpu執(zhí)行的狀態(tài),相當(dāng)于我們?cè)谟脩舫绦蚣?jí)別將自己的io操作最大限度地隱藏起來(lái),從而可以迷惑操作系統(tǒng),讓其看到:該線程好像是一直在計(jì)算,io比較少,從而更多的將cpu的執(zhí)行權(quán)限分配給我們的線程。

協(xié)程的本質(zhì)就是在單線程下,由用戶自己控制一個(gè)任務(wù)遇到io阻塞了就切換另外一個(gè)任務(wù)去執(zhí)行,以此來(lái)提升效率。為了實(shí)現(xiàn)它,我們需要找尋一種可以同時(shí)滿足以下條件的解決方案:

1. 可以控制多個(gè)任務(wù)之間的切換,切換之前將任務(wù)的狀態(tài)保存下來(lái),以便重新運(yùn)行時(shí),可以基于暫停的位置繼續(xù)執(zhí)行。
2. 作為1的補(bǔ)充:可以檢測(cè)io操作,在遇到io操作的情況下才發(fā)生切換

協(xié)程介紹

協(xié)程:是單線程下的并發(fā),又稱(chēng)微線程,纖程。英文名Coroutine。一句話說(shuō)明什么是線程:協(xié)程是一種用戶態(tài)的輕量級(jí)線程,即協(xié)程是由用戶程序自己控制調(diào)度的。
需要強(qiáng)調(diào)的是:

1. python的線程屬于內(nèi)核級(jí)別的,即由操作系統(tǒng)控制調(diào)度(如單線程遇到io或執(zhí)行時(shí)間過(guò)長(zhǎng)就會(huì)被迫交出cpu執(zhí)行權(quán)限,切換其他線程運(yùn)行)
2. 單線程內(nèi)開(kāi)啟協(xié)程,一旦遇到io,就會(huì)從應(yīng)用程序級(jí)別(而非操作系統(tǒng))控制切換,以此來(lái)提升效率(?。。》莍o操作的切換與效率無(wú)關(guān))

對(duì)比操作系統(tǒng)控制線程的切換,用戶在單線程內(nèi)控制協(xié)程的切換
優(yōu)點(diǎn)如下:

1. 協(xié)程的切換開(kāi)銷(xiāo)更小,屬于程序級(jí)別的切換,操作系統(tǒng)完全感知不到,因而更加輕量級(jí)
2. 單線程內(nèi)就可以實(shí)現(xiàn)并發(fā)的效果,最大限度地利用cpu

缺點(diǎn)如下:

1. 協(xié)程的本質(zhì)是單線程下,無(wú)法利用多核,可以是一個(gè)程序開(kāi)啟多個(gè)進(jìn)程,每個(gè)進(jìn)程內(nèi)開(kāi)啟多個(gè)線程,每個(gè)線程內(nèi)開(kāi)啟協(xié)程
2. 協(xié)程指的是單個(gè)線程,因而一旦協(xié)程出現(xiàn)阻塞,將會(huì)阻塞整個(gè)線程

總結(jié)協(xié)程特點(diǎn):

1.必須在只有一個(gè)單線程里實(shí)現(xiàn)并發(fā)
2.修改共享數(shù)據(jù)不需加鎖
3.用戶程序里自己保存多個(gè)控制流的上下文棧
4.一個(gè)協(xié)程遇到IO操作自動(dòng)切換到其它協(xié)程(如何實(shí)現(xiàn)檢測(cè)IO,yield、greenlet都無(wú)法實(shí)現(xiàn),就用到了gevent模塊(select機(jī)制))   
Gevent模塊

安裝:pip3 install gevent
Gevent 是一個(gè)第三方庫(kù),可以輕松通過(guò)gevent實(shí)現(xiàn)并發(fā)同步或異步編程,在gevent中用到的主要模式是Greenlet, 它是以C擴(kuò)展模塊形式接入Python的輕量級(jí)協(xié)程。 Greenlet全部運(yùn)行在主程序操作系統(tǒng)進(jìn)程的內(nèi)部,但它們被協(xié)作式地調(diào)度。
用法介紹

g1=gevent.spawn(func,1,,2,3,x=4,y=5)創(chuàng)建一個(gè)協(xié)程對(duì)象g1,spawn括號(hào)內(nèi)第一個(gè)參數(shù)是函數(shù)名,
如eat,后面可以有多個(gè)參數(shù),可以是位置實(shí)參或關(guān)鍵字實(shí)參,都是傳給函數(shù)eat的

g2=gevent.spawn(func2)

g1.join() #等待g1結(jié)束

g2.join() #等待g2結(jié)束

#或者上述兩步合作一步:gevent.joinall([g1,g2])

g1.value#拿到func1的返回值

例:遇到io主動(dòng)切換

import gevent
def eat(name):
    print("%s eat 1" %name)
    gevent.sleep(2)
    print("%s eat 2" %name)

def play(name):
    print("%s play 1" %name)
    gevent.sleep(1)
    print("%s play 2" %name)


g1=gevent.spawn(eat,"egon")
g2=gevent.spawn(play,"egon")
g1.join()
g2.join()
#或者gevent.joinall([g1,g2])
print("主")

上例gevent.sleep(2)模擬的是gevent可以識(shí)別的io阻塞,而time.sleep(2)或其他的阻塞,gevent是不能直接識(shí)別的需要用下面一行代碼,打補(bǔ)丁,就可以識(shí)別了

from gevent import monkey;monkey.patch_all()必須放到被打補(bǔ)丁者的前面,如time,socket模塊之前

或者我們干脆記憶成:要用gevent,需要將from gevent import monkey;monkey.patch_all()放到文件的開(kāi)頭

from gevent import monkey;monkey.patch_all()

import gevent
import time
def eat():
    print("eat food 1")
    time.sleep(2)
    print("eat food 2")

def play():
    print("play 1")
    time.sleep(1)
    print("play 2")

g1=gevent.spawn(eat)
g2=gevent.spawn(play)
gevent.joinall([g1,g2])
print("主")

我們可以用threading.current_thread().getName()來(lái)查看每個(gè)g1和g2,查看的結(jié)果為DummyThread-n,即假線程

from gevent import monkey;monkey.patch_all()
import threading
import gevent
import time
def eat():
    print(threading.current_thread().getName())
    print("eat food 1")
    time.sleep(2)
    print("eat food 2")

def play():
    print(threading.current_thread().getName())
    print("play 1")
    time.sleep(1)
    print("play 2")

g1=gevent.spawn(eat)
g2=gevent.spawn(play)
gevent.joinall([g1,g2])
print("主")
Gevent之同步與異步
from gevent import spawn, joinall, monkey;monkey.patch_all()
import time
def task(pid):
    """
    Some non-deterministic task
    """
    time.sleep(0.5)
    print("Task %s done" % pid)


def synchronous():  # 同步
    for i in range(10):
        task(i)
def asynchronous():  # 異步
    g_l = [spawn(task, i) for i in range(10)]
    joinall(g_l)
    print("DONE")
if __name__ == "__main__":
    print("Synchronous:")
    synchronous()
    print("Asynchronous:")
    asynchronous()
#  上面程序的重要部分是將task函數(shù)封裝到Greenlet內(nèi)部線程的gevent.spawn。
#  初始化的greenlet列表存放在數(shù)組threads中,此數(shù)組被傳給gevent.joinall 函數(shù),
#  后者阻塞當(dāng)前流程,并執(zhí)行所有給定的greenlet任務(wù)。執(zhí)行流程只會(huì)在 所有g(shù)reenlet執(zhí)行完后才會(huì)繼續(xù)向下走。
協(xié)程socket
from gevent import monkey;monkey.patch_all()
import socket
import gevent

def talk(conn):
    while True:
        conn.send(b"hello")
        print(conn.recv(1024))

sk = socket.socket()
sk.bind(("127.0.0.1",9090))
sk.listen()

while True:
    conn,addr = sk.accept()
    g = gevent.spawn(talk,conn)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/42185.html

相關(guān)文章

  • Python協(xié)程(真才實(shí)學(xué),想學(xué)的進(jìn)來(lái))

    摘要:所以與多線程相比,線程的數(shù)量越多,協(xié)程性能的優(yōu)勢(shì)越明顯。值得一提的是,在此過(guò)程中,只有一個(gè)線程在執(zhí)行,因此這與多線程的概念是不一樣的。 真正有知識(shí)的人的成長(zhǎng)過(guò)程,就像麥穗的成長(zhǎng)過(guò)程:麥穗空的時(shí)候,麥子長(zhǎng)得很快,麥穗驕傲地高高昂起,但是,麥穗成熟飽滿時(shí),它們開(kāi)始謙虛,垂下麥芒。 ——蒙田《蒙田隨筆全集》 上篇論述了關(guān)于python多線程是否是雞肋的問(wèn)題,得到了一些網(wǎng)友的認(rèn)可,當(dāng)然也有...

    lykops 評(píng)論0 收藏0
  • 異步等待的 Python 協(xié)程

    摘要:輔之以事件循環(huán),協(xié)程可用于異步處理,尤其是在中。當(dāng)前支持的協(xié)程基于增強(qiáng)型生成器,于版本開(kāi)始采用。新的特性中,異步還有兩種新用途異步內(nèi)容管理器和迭代器。 現(xiàn)在 Python 已經(jīng)支持用協(xié)程進(jìn)行異步處理。但最近有建議稱(chēng)添加協(xié)程以全面完善 Python 的語(yǔ)言結(jié)構(gòu),而不是像現(xiàn)在這樣把他們作為生成器的一個(gè)類(lèi)型。此外,兩個(gè)新的關(guān)鍵字———異步(async)和等待(await),都該添加到 Pyt...

    NicolasHe 評(píng)論0 收藏0
  • python協(xié)程與golang協(xié)程的區(qū)別

    摘要:進(jìn)程線程和協(xié)程進(jìn)程的定義進(jìn)程,是計(jì)算機(jī)中已運(yùn)行程序的實(shí)體。協(xié)程和線程的關(guān)系協(xié)程是在語(yǔ)言層面實(shí)現(xiàn)對(duì)線程的調(diào)度,避免了內(nèi)核級(jí)別的上下文消耗。和都引入了消息調(diào)度系統(tǒng)模型,來(lái)避免鎖的影響和進(jìn)程線程開(kāi)銷(xiāo)大的問(wèn)題。 進(jìn)程、線程和協(xié)程 進(jìn)程的定義: 進(jìn)程,是計(jì)算機(jī)中已運(yùn)行程序的實(shí)體。程序本身只是指令、數(shù)據(jù)及其組織形式的描述,進(jìn)程才是程序的真正運(yùn)行實(shí)例。 線程的定義: 操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單...

    csRyan 評(píng)論0 收藏0
  • python基礎(chǔ)教程:異步IO 之編程例子

    摘要:創(chuàng)建第一個(gè)協(xié)程推薦使用語(yǔ)法來(lái)聲明協(xié)程,來(lái)編寫(xiě)異步應(yīng)用程序。協(xié)程兩個(gè)緊密相關(guān)的概念是協(xié)程函數(shù)通過(guò)定義的函數(shù)協(xié)程對(duì)象調(diào)用協(xié)程函數(shù)返回的對(duì)象。它是一個(gè)低層級(jí)的可等待對(duì)象,表示一個(gè)異步操作的最終結(jié)果。 我們講以Python 3.7 上的asyncio為例講解如何使用Python的異步IO。 showImg(https://segmentfault.com/img/remote/14600000...

    wangxinarhat 評(píng)論0 收藏0
  • python大佬養(yǎng)成計(jì)劃----協(xié)程

    摘要:協(xié)程,又稱(chēng)微線程,纖程。最大的優(yōu)勢(shì)就是協(xié)程極高的執(zhí)行效率。生產(chǎn)者產(chǎn)出第條數(shù)據(jù)返回更新值更新消費(fèi)者正在調(diào)用第條數(shù)據(jù)查看當(dāng)前進(jìn)行的線程函數(shù)中有,返回值為生成器庫(kù)實(shí)現(xiàn)協(xié)程通過(guò)提供了對(duì)協(xié)程的基本支持,但是不完全。 協(xié)程,又稱(chēng)微線程,纖程。英文名Coroutine協(xié)程看上去也是子程序,但執(zhí)行過(guò)程中,在子程序內(nèi)部可中斷,然后轉(zhuǎn)而執(zhí)行別的子程序,在適當(dāng)?shù)臅r(shí)候再返回來(lái)接著執(zhí)行。 最大的優(yōu)勢(shì)就是協(xié)程極高...

    svtter 評(píng)論0 收藏0
  • 談?wù)?em>Python協(xié)程技術(shù)的演進(jìn)

    摘要:事件循環(huán)是異步編程的底層基石。對(duì)事件集合進(jìn)行輪詢(xún),調(diào)用回調(diào)函數(shù)等一輪事件循環(huán)結(jié)束,循環(huán)往復(fù)。協(xié)程直接利用代碼的執(zhí)行位置來(lái)表示狀態(tài),而回調(diào)則是維護(hù)了一堆數(shù)據(jù)結(jié)構(gòu)來(lái)處理狀態(tài)。時(shí)代的協(xié)程技術(shù)主要是,另一個(gè)比較小眾。 Coding Crush Python開(kāi)發(fā)工程師 主要負(fù)責(zé)豈安科技業(yè)務(wù)風(fēng)險(xiǎn)情報(bào)系統(tǒng)redq。 引言 1.1. 存儲(chǔ)器山 存儲(chǔ)器山是 Randal Bryant 在《深入...

    zhiwei 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

lolomaco

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<