溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何理解python的yeild,async,azwait和協(xié)程

發(fā)布時間:2021-10-08 11:29:50 來源:億速云 閱讀:234 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“如何理解python的yeild,async,azwait和協(xié)程”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“如何理解python的yeild,async,azwait和協(xié)程”吧!

目錄
  • 一、yield使用簡析

  • 二、async和await的使用

    • 1.什么是進(jìn)程、協(xié)程、異步?

    • 2.如何處理200W數(shù)量的url,把所有的url保存下來?

    • 3.使用async的await和gather

  • 三、協(xié)程的理解

    一、yield使用簡析

    yield是一個生成器generator,返回一個interable對象。

    該對象具有next()方法,可以通過next()查看接下來的元素是什么。

    1.interable對象 ,可以遍歷的對象,如: list,str,tuple,dict,file,xrange等。

    2.yield的作用是什么?只是循環(huán)里面的獲取中間變量的一個方法,把想要的變量每次使用yield保存起來直至循環(huán)結(jié)束,循環(huán)結(jié)束得到了一個generator對象

    3.為什么使用yield?使用yield,一個函數(shù)改寫成generator,便具有了迭代的能力,比起用類的實例保存狀態(tài)計算下一個需要迭代的值,代碼更加簡潔,執(zhí)行流程十分簡單。

    4.如何判斷yield的類型?

    def fab(max): 
        n, a, b = 0, 0, 1 
        while n < max: 
            yield b      # 使用 yield
            # print b 
            a, b = b, a + b 
            n = n + 1
    for n in fab(5): 
        print n

    fab不是generator,fab(5)是generator。

    好比類的定義和類的實例的區(qū)別。

    >>>import types 
    >>> isinstance(fab, types.GeneratorType) 
    False 
    >>> isinstance(fab(5), types.GeneratorType) 
    True

    fab 是無法迭代的,而 fab(5) 是可迭代的。

    >>>from collections import Iterable 
    >>> isinstance(fab, Iterable) 
    False 
    >>> isinstance(fab(5), Iterable) 
    True

    5.yield在文件讀取的應(yīng)用?

    如果字節(jié)使用read()讀取一個文件,會導(dǎo)致不可預(yù)測的內(nèi)存占用。好的方法是使用yield,固定長度的緩沖區(qū)來不斷讀取文件,生成讀文件的迭代的generator。

    def read_file(fpath): 
        BLOCK_SIZE = 1024 
        with open(fpath, 'rb') as f: 
            while True: 
                block = f.read(BLOCK_SIZE) 
                if block: 
                    yield block 
                else: 
                    return

    二、async和await的使用

    1.什么是進(jìn)程、協(xié)程、異步?

    • 協(xié)程是什么?

    一種用戶級輕量級的線程,擁有自己的寄存器上下文和棧。

    協(xié)程切換時候,將寄存器和棧保存在其他地方,當(dāng)返回的時候,恢復(fù)原先保存的寄存器上下文和棧。

    • 為什么使用協(xié)程?

    主流語言采用多線程并發(fā),線程相關(guān)的概念是搶占式多任務(wù),協(xié)程相關(guān)的協(xié)作式多任務(wù)。

    不管是多進(jìn)程還是多線程,每次阻塞、切換陷入系統(tǒng)調(diào)用。

    CPU跑操作系統(tǒng)的調(diào)度程序,調(diào)度程序決定運行哪一個進(jìn)程(線程)。

    線程非常小心的處理同步問題,而協(xié)程完全不存在這個問題。

    對于CPU而言,多協(xié)程是單線程,CPU不會考慮調(diào)度、切換上下文,省去CPU的切換開銷。協(xié)程好于多線程的原因。

    • 如何使用協(xié)程?

    多進(jìn)程+協(xié)程下,避開了CPU切換的開銷,又能把多個CPU充分利用起來,這種方式對于數(shù)據(jù)量較大的爬蟲還有文件讀寫之類的效率提升是巨大的。

    2.如何處理200W數(shù)量的url,把所有的url保存下來?

    • 單進(jìn)程+單線程

    • 單進(jìn)程+多線程:開十個線程,速度不能提高十倍。線程的切換是有開銷的,無能無限的創(chuàng)建線程。

    • 多進(jìn)程+多線程:多進(jìn)程的每個進(jìn)程占用一個CPU,多線程一定程度上繞過了阻塞時間,所以相比單進(jìn)程的多線程效率更高。

    • 協(xié)程

    3.使用async的await和gather

    • await接受一個協(xié)程列表,返回done、pending兩個列表。done是已經(jīng)完成的協(xié)程,pending是仍在跑的協(xié)程。通過.result()獲取完成的結(jié)果

    • gather以gather(cro1, cro2, cro3, cro4…)的方式接受協(xié)程,返回的是一個結(jié)合了這么多個任務(wù)的協(xié)程。

    async的使用:https://blog.csdn.net/qq_29785317/article/details/103294235

    async def func1(num):
        print('--func1 start--')
        await asyncio.sleep(num)
        print('--func1 done--')
        return 'func1 ok'
    async def func2(num):
        print('--func2 start--')
        await asyncio.sleep(num)
        print('--func2 done--')
        return 'func2 ok'
    async def main():
        task1 = asyncio.ensure_future(func1(3))
        task2 = asyncio.ensure_future(func2(5))
        tasks = [task1, task2]
        res = await asyncio.gather(*tasks)
        return res
        # done, pending = await asyncio.wait(tasks)
        # for t in done:
        #     print(t.result())
        # print(done)
        # print(pending)
    if __name__ == '__main__':
        loop = asyncio.get_event_loop()
        result = loop.run_until_complete(main())
        print(result)
    ```python
    --func1 start--
    --func2 start--
    --func1 done--
    --func2 done--
    ['func1 ok', 'func2 ok']

    三、協(xié)程的理解

    1.協(xié)程的過程

    協(xié)程中yield是控制流程的方式。

    yield同接收器一樣,是一個生成器,需要先激活才能使用。

    >>> def simple_corotine():
    ...     print('---->coroutine started')
    ...     x = yield  #有接收值,所以同生成器一樣,需要先激活,使用next
    ...     print('---->coroutine recvied:',x)
    ...
    >>> my_coro = simple_corotine()
    >>> my_coro
    <generator object simple_corotine at 0x0000000000A8A518>
    >>> next(my_coro)  #先激活生成器,執(zhí)行到y(tǒng)ield val語句  #或者使用send(None)也可以激活生成器
    ---->coroutine started
    >>> my_coro.send(24)  #向其中傳入值,x = yield
    ---->coroutine recvied: 24
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration  #當(dāng)生成器執(zhí)行完畢時會報錯

    2.協(xié)程在運行中的四種狀態(tài)

    GEN_CREATE:等待開始執(zhí)行

    GEN_RUNNING:解釋器正在執(zhí)行,這個狀態(tài)一般看不到

    GEN_SUSPENDED:在yield表達(dá)式處暫停

    GEN_CLOSED:執(zhí)行結(jié)束

    >>> def averager():
    ...     total = 0.0
    ...     count = 0
    ...     aver = None
    ...     while True:
    ...             term = yield aver
    ...             total += term
    ...             count += 1
    ...             aver = total/count
    ...
    >>> coro_avg = averager()
    >>> coro_avg.send(None)
    >>> coro_avg.send(10)
    10.0
    >>> coro_avg.send(20)
    15.0
    >>> coro_avg.send(30)
    20.0
    >>> coro_avg.send(40)
    25.0

    每次循環(huán)結(jié)束在yield出暫停,直至下一個參數(shù)傳進(jìn)來。

    3.預(yù)激活協(xié)程的裝飾器(自定義激活的方式)

    @裝飾器的作用是什么?裝飾原有的函數(shù),給原油函數(shù)增加一個新的功能和方式。

    為什么@可以實現(xiàn)裝飾器的功能?函數(shù)也是對象,函數(shù)可以作為實參傳給掐函數(shù)。

    >>> def coro_active(func):
    ...     def inner(*args,**kwargs):
    ...         gen = func(*args,**kwargs)
    ...         next(gen)   #gen.send(None)
    ...         return gen
    ...     return inner
    ...
    >>> @coro_active
    ... def averager():
    ...     total = 0.0
    ...     count = 0
    ...     aver = None
    ...     while True:
    ...             term = yield aver
    ...             total += term
    ...             count += 1
    ...             aver = total/count
    ...
    >>> coro_avg = averager()
    >>> coro_avg.send(10) 10.0 >>> coro_avg.send(20) 15.0 >>> coro_avg.send(30) 20.0

    4.終止協(xié)程和異常處理

    當(dāng)協(xié)程的next函數(shù)或者send函數(shù)發(fā)生錯誤的時候,協(xié)程就會終止掉。

    需要創(chuàng)建異常捕捉對協(xié)程的異常情況進(jìn)行處理,關(guān)閉當(dāng)前協(xié)程。

    5.讓協(xié)程返回值

    yield使用方法 ??

    到此,相信大家對“如何理解python的yeild,async,azwait和協(xié)程”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI