• 请不要在回答技术问题时复制粘贴 AI 生成的内容
balabalaguguji
V2EX  ›  程序员

Python3 写异步 IO 方便吗?跟 NodeJS 比,有哪些不足之处。

  •  1
     
  •   balabalaguguji · Aug 23, 2021 · 5103 views
    This topic created in 1898 days ago, the information mentioned may be changed or developed.

    最近了解了下 Python3 的 async/await 用起来跟 NodeJS 的差不多,找到的异步 Redis 和 Mongodb 库都还不错。

    发现 requests 没有异步,想找个替代的,aiohttp 的语法太奇怪了,如下,得先创建一个 session,然后 xxx,写起来很是麻烦,特别是要把以前的同步代码改为异步的,突然想要放弃。

    import aiohttp
    import asyncio
    
    async def main():
        async with aiohttp.ClientSession() as session:
            pokemon_url = 'https://pokeapi.co/api/v2/pokemon/151'
            async with session.get(pokemon_url) as resp:
                pokemon = await resp.json()
                print(pokemon['name'])
    
    asyncio.run(main())
    

    NodeJS 的 Promise 就非常爽,没有异步的自己包装下就好了,像 sleep 。

    34 replies  •  2021-08-25 09:58:09 +08:00
    Vegetable
    Vegetable
    Aug 23, 2021
    1
    异步网络请求库都是这模样。
    https://github.com/encode/httpx

    > HTTPX builds on the well-established usability of requests
    HongTang
    HongTang
    Aug 23, 2021
    2
    python 不是假并发吗
    kasheemlew
    kasheemlew
    Aug 23, 2021
    3
    python 也可以这样:

    ```python
    import asyncio
    import requests

    async def main():
    loop = asyncio.get_event_loop()
    futures = [
    loop.run_in_executor(None, requests.get, 'http://www.baidu.com')
    for _ in range(100)
    ]
    await asyncio.gather(*futures)

    asyncio.run(main())
    ```
    libook
    libook
    Aug 23, 2021
    4
    只要从同步代码重构为 async/await,基本都是要一层一层都改成 async/await 写法,包括 JS 在内的各个语言都是这样的。

    aiohttp 的这个流程跟 Node.js 的 http module 基本是一致的,都是:
    1. 创建 HTTP 客户端;
    2. 创建请求;
    3. 向请求流中写入数据,然后发送流结束;
    4. 从返回流接收数据,直到流结束。
    balabalaguguji
    balabalaguguji
    OP
    Aug 23, 2021
    5
    @libook #4 axios 好用,python 没找到那么好用的。
    LeeReamond
    LeeReamond
    Aug 23, 2021❤️2
    6
    1 、requests 的正常用法也包括创建 session,不用只是因为写的 demo 需求场景太简单了而已。

    2 、因为 Python 存在同步宇宙与异步宇宙两种东西,你要在同步宇宙里创造异步宇宙 j 就需要手搓一个事件循环,所以采用了这种写法。node 的事件循环是与生俱来送给你的,所以你在 node 中不需要额外写法,但同样地这令进入同步宇宙变得困难。

    3 、Python 也可以非常简单地将同步逻辑封装为协程。
    aladdinding
    aladdinding
    Aug 23, 2021
    7
    使用了 session 应该是会和浏览器一样进行 tcp 的连接复用 跟浏览器一样
    aladdinding
    aladdinding
    Aug 23, 2021
    8
    requests 也有 session
    janxin
    janxin
    Aug 23, 2021
    9
    最大问题是侵入性的,至少要做额外适配

    客户端推荐 httpx
    keepeye
    keepeye
    Aug 23, 2021
    10
    自己可以封装一下,例如

    async def post(url, data: bytes, proxy=None, **kwargs):
    async with aiohttp.ClientSession().post(url, data=data, proxy=proxy, **kwargs) as response:
    return response
    keepeye
    keepeye
    Aug 23, 2021
    11
    缩进怎么没了 ,谁知道评论怎么发代码?
    ```
    async def post(url, data: bytes, proxy=None, **kwargs):
    async with aiohttp.ClientSession().post(url, data=data, proxy=proxy, **kwargs) as response:
    return response
    ```
    balabalaguguji
    balabalaguguji
    OP
    Aug 23, 2021
    12
    @keepeye #10 好嘞,感谢
    ClericPy
    ClericPy
    Aug 23, 2021
    13
    我是自己缓存一个 Session 对象然后到处引用...

    比如这句 async with aiohttp.ClientSession() as session 拆成 self.session = aiohttp.ClientSession() 然后 await self.session.__aenter__() 到 结束时候 await self.session.__aexit__(None, None None) 就行了

    用起来还凑合吧, 至于 httpx, 性能比 aiohttp 差一倍多, 不得不选了后者, 然后自己加了 wrapper 把 aiohttp 打包成 requests 那个用法...
    ysc3839
    ysc3839
    Aug 23, 2021 via Android❤️1
    14
    @LeeReamond “需要手搓一个事件循环”这是 Python 加的限制。理论上无栈协程是可以直接替代回调函数使用的,不需要什么事件循环。比如 C++的协程在 await 一个对象的时候,被 await 的对象能拿到这个协程的回调函数,执行这个回调函数就能恢复协程执行。
    js 也与此类似,它的异步跟事件循环关系并不大。
    但是 Python 的不一样,它一定要一个事件循环或者说调度器才能跑起来,不能像 C++那样让被等待方控制恢复执行。
    ericls
    ericls
    Aug 23, 2021
    15
    测过 uvloop 性能和 nodejs 一模一样. 但是 CPU heavy 的东西还是慢一些
    crclz
    crclz
    Aug 23, 2021
    16
    一点也不奇怪,每一个 async,await 都有其存在的价值。只要理解了就好了。

    https://gist.github.com/crclz/2308cc72cc3f37836a6cab22c1981849
    iyaozhen
    iyaozhen
    Aug 23, 2021
    17
    个人感觉新业务可以用
    但前提你要保证你自己确实对这个深入理解了,不然出问题没人帮你 java 那帮人不了解这个

    因为 Python 天生是同步的,一旦出了问题你就得背锅了,之前有个对口的同事就这样走人了
    simple2025
    simple2025
    Aug 23, 2021
    18
    @iyaozhen 这么惨?
    kuangwinnie
    kuangwinnie
    Aug 24, 2021
    19
    @keepeye 评论不能发代码
    abersheeran
    abersheeran
    Aug 24, 2021❤️1
    20
    跟 Nodejs 比的不足之处大抵在于 Nodejs 天然自带一个 loop,Python 需要你显式创建 loop 。而且 Nodejs 里原生都是异步的,不需要自己注意。Python 里原生都是同步的,需要自己时刻注意。
    qW7bo2FbzbC0
    qW7bo2FbzbC0
    Aug 24, 2021
    21
    @crclz #16 最新的 HTTPClient 不是自带 async 方法了吗
    Nich0la5
    Nich0la5
    Aug 24, 2021
    22
    python 异步几个蛋疼的点 await 传染,具体的异步实现依赖于第三方库而且场景覆盖不全,像 aiohttp aiofile 一直有海量 bug,( httpx 相对好一些维护的人比较多),自己从头撸一个异步库又要从底开始太麻烦了,我就是嫌麻烦才用 py 的。我自己写的时候经常是线程协程混写,只有明显协程性能占优的场景才用。

    至于你说的 session 问题,request 也有,而且推荐这种写法,你可以自己测下性能,复用 session 和不带的差距还是很大的
    wangyzj
    wangyzj
    Aug 24, 2021
    23
    天生异步和假异步
    python 不是干这个的
    能写而已
    sss007
    sss007
    Aug 24, 2021
    24
    python 写轮询 http 都能假死。。。
    enrolls
    enrolls
    Aug 24, 2021
    25
    使用 3.9 版本,語法會變簡單。或者試試
    enrolls
    enrolls
    Aug 24, 2021
    26
    使用 3.9 版本,語法會變簡單。或者試試 curio
    mmdsun
    mmdsun
    Aug 24, 2021 via Android
    27
    async/await 还是 C sharp 最舒服。

    其他语言有 async/await 但没学到 C#异步的精髓。
    meiyoumingzi6
    meiyoumingzi6
    Aug 24, 2021
    28
    主要还是生态吧, 感觉写起来好点, 单还是不太爽
    还是 golang 写异步爽的起飞
    Trim21
    Trim21
    Aug 24, 2021
    29
    如果你要替换 requests 的话应可以用 httpx.AsyncClient,基本上就是把 requests.Session 的 http 请求换成了异步的。

    如果是长时间运行的服务的话本来就不应该用 requests.get ,应该整个程序初始化一个或者多个 requests.Session,然后复用 session,跟 aiohttp 强制你要做的事情是差不多的,aiohttp 的文档里面也提到了不要每次请求都创建一个 session
    lewinlan
    lewinlan
    Aug 25, 2021 via Android
    30
    都 2021 年了,还写 py,放过自己好吗?
    balabalaguguji
    balabalaguguji
    OP
    Aug 25, 2021
    31
    @Trim21 #29 好的,多谢。我的连接都是一次一个的,似乎没必要保持一个 session
    molika
    molika
    Aug 25, 2021
    32
    习惯就好了 ~ 可能需要注意的就是各种三方库了 好多都是同步的。要自己 hack 打补丁 很痛苦。
    gitopen
    gitopen
    Aug 25, 2021
    33
    @lewinlan 不写 py,写啥
    balabalaguguji
    balabalaguguji
    OP
    Aug 25, 2021
    34
    @molika #32 想想还是放弃了
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   1447 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 68ms · UTC 18:26 · PVG 02:26 · LAX 10:26 · JFK 13:26
    ♥ Do have faith in what you're doing.