Python 的協程到底有啥用啊…

Python nightan • at 2020-03-24 22:06:42 • 10 Views
看了好多文章,也自己嘗試用了用協程,但是感覺對程式的執行效率並沒什麼太大的提升…
我原以為我可以在通過 HTTP 取資料的這個時間內讓程式去處理別的邏輯,處理完後再回來處理取回來的資料…
可能是我太菜了…(捂臉)
Total: 44
  • LokiSharp 2020-03-23 23:28:19
    你得所有都非同步非阻塞才行
  • ClericPy 2020-03-23 23:25:20
    全域性協程寫起來有爽的地方也有不習慣的地方, 爽的基本就是全程非阻塞了, 以前多執行緒處理的事情全丟給 Future/Task, 整個程式基本不會因為一句程式碼影響其他程式碼(寫錯的情況下還是可能的... 比如錯用 time.sleep). 不爽的地方就是程式不能自己識別自己要不要 await 一個結果, 害我為了相容普通函式和協程的執行結果, 總得

    result = (await result) if isawaitable(result) else xxx

    效能的話, 不開 uvloop 感覺不出太明顯差距
  • mimzy 2020-03-24 00:24:20
    用同步的思維寫非同步程式
    減少鎖、上下文切換、執行緒自身的開銷
  • mimzy 2020-03-24 00:24:20
    For I/O-bound workloads, there are exactly (only!) two reasons to use async-based concurrency over thread-based concurrency:

    - Asyncio offers a safer alternative to preemptive multitasking (i.e., using threads), thereby avoiding the bugs, race conditions, and other nondeterministic dangers that frequently occur in nontrivial threaded applications.

    - Asyncio offers a simple way to support many thousands of simultaneous socket connections, including being able to handle many long-lived connections for newer technologies like WebSockets, or MQTT for Internet of Things (IoT) applications.

    摘自 Using Asyncio in Python 昨天剛好看了這本書 如果感興趣且能看到的話可以看下 還是挺不錯的 http://shop.oreilly.com/product/0636920320876.do
  • zhuangzhuang1988 2020-03-24 00:28:20
  • xingheng 2020-03-24 01:27:20
    協程的意義在意執行多個沒有上下文結果依賴的“不相關”的任務的時候會讓這些任務並行執行,同時又不需要擔心執行緒的狀態管理,以此達到執行效率的提升。
    但是,有一種情況下協程並不會提升效率,理論上反而會降低效率(因為執行緒切換的代價)。

    async def run(tasks):
    all_results = []
    for task in tasks:
    result = await execute(task) # the only one await
    all_results.append(result) # append logic result of execute, not task itself

    return all_results

    不是特別好的一個例子。只有一個 await task 的話,後續操作又需要拿到結果才能繼續,相當於同步的 join 卡在了 caller 所在的執行緒,沒有非同步的意義,所以會更慢。當然,基於上面的例子要優化也是非常簡單的,不寫了
  • sylvos 2020-03-24 07:26:41
    @xingheng 還請寫下優化的程式碼
  • janxin 2020-03-24 08:24:41
    因為沒有理解併發並行的含義吧...
  • YUX 2020-03-24 08:20:41
    https://hatboy.github.io/2019/02/16/Python 非同步程式設計詳解 /

    推薦一篇好文章
  • nightan 2020-03-24 09:20:41
    @xingheng 我好像就是寫了個這樣的東西(捂臉)
  • nightan 2020-03-24 09:20:41
    @YUX 大佬 404 了這個……
  • nightan 2020-03-24 10:22:41
    @xingheng 大佬,求優化的例子……
  • jatsz 2020-03-24 10:22:41
    協程-主要還是保持狀態,像你這種還是需要非同步 IO,asyncio 。
    在應用上,主要還是生成器,比如你處理未知網路資料,你可以使用協程去迭代處理。
    https://www.imzjy.com/blog/2015-01-01-coroutine
  • itskingname 2020-03-24 10:23:41
    我寫了一篇文章來說明你遇到的問題。https://mp.weixin.qq.com/s/spayiLNuTnFVOWWeW-jkwQ

    注意文中為了照顧沒有基礎的讀者,有些概念可能並不十分準確,但是表達意思。
  • bnm965321 2020-03-24 10:25:41
    當然可以在 HTTP 取資料的時間幹其他的事情,就算是做 CPU bound 的事情也可以。如果你從頭寫一個爬蟲,一次多發一些 HTTP request 就知道了。HTTP 堵塞的那些時間,CPU 是可以做很多很多事情的
  • smallgoogle 2020-03-24 10:26:41
    反正我知道協程速度快很多就對了。
  • freakxx 2020-03-24 11:23:42
    > 這個時間內讓程式去處理別的邏輯,處理完後再回來處理取回來的資料

    這個地方讀起來有些怪


    之前是寫了一個 chunk + requests_async 用協程處理

    你可以這麼理解

    for _ in range(100):
    request


    for _ in range(100):
    request_async


    這兩者會有區別。

    但如果
    你只是請求一個並直接使用,不一定有你要的效果。
  • vicalloy 2020-03-24 11:23:42
    協程是單執行緒的,因此你必須保證你的所有“阻塞”操作都是非同步的,不然對效能沒有任何提升。
    比如你用 requests 寫爬蟲程式。由於 requests 的操作都是阻塞的,用協程不會帶來任何的效能提升。
    要想提升效能得把 requests 換成非阻塞的庫,如 aiohttp 。
  • YUX 2020-03-24 11:24:42
    也可以試試 multiprocessing
  • nightan 2020-03-24 14:26:42
    @YUX 感謝大佬的分享,前後大概看得懂……中間看的懵圈……(捂臉),我得慢慢消化消化……
    我現在寫的程式中,實際上有三個函式,分別負責——
    - 1. 從某個資料庫讀資料,存下來
    - 2. 處理這些資料,然後寫到另一個庫中,同時這些處理後的資料還要讓第三個函式拿到
    - 3. 把處理後的資料通過 HTTP 傳送出去
    也許我可以把這三個函式放到三個執行緒中?其中一個函式發生 I/O 操作的時候,其它函式應該會執行吧……?
  • YUX 2020-03-24 15:21:18
    @nightan #22 正如前面多次提到的 要全域性都非阻塞 不知道你這三個函式是否都滿足要求 推薦一個 非阻塞的 orm https://github.com/tortoise/tortoise-orm
  • Orenoid 2020-03-24 15:24:18
    推薦一篇文章,https://snarky.ca/how-the-heck-does-async-await-work-in-python-3-5/
    作者從頭講解了 Python 協程的工作原理,並實現了一個簡易的事件迴圈,有助於理解基於 Python 協程的工作原理。
    但是這個說的是原理,目前可能不太適合你看。之後有興趣可以看下,看完可以再讀下 asyncio 庫的原始碼。
    Python 協程本質是依賴 IO 多路複用和 yield 去實現非同步的,所以只有網路 IO 才有必要使用協程。
  • nightan 2020-03-24 15:17:18
    @YUX 發 HTTP 請求用的 requests 模組,看起來是阻塞的,剛剛我也試過,await 對於這個模組的呼叫不生效; 所以即使我用多執行緒,在處理 HTTP 請求的時候,因為是阻塞的,也一定是要等它執行完是嗎?阻塞的 I/O 發生時,python 也不能切換到別的執行緒咯……
  • crackhopper 2020-03-24 16:25:18
    你得整體在一個非同步框架裡,才有意義。比如事件驅動的框架。
  • xcstream 2020-03-24 17:23:18
    無鎖併發
  • nightan 2020-03-24 19:22:50
    @freakxx 謝謝
  • hehheh 2020-03-24 20:23:50
    我以前寫過一個代理 ip 池,測試 1000 個 IP 。如果是多執行緒大概需要 2 分鐘,如果是協程大概 10 秒。
Add a reply
For Commenting you need to Login. If you dont have a Account you need to Register.