求解, python3.5 的 asyncio 库, async/await 的一些疑惑 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
fghjghf
V2EX    Python

求解, python3.5 的 asyncio 库, async/await 的一些疑惑

  •  
  •   fghjghf 2020-04-15 18:14:28 +08:00 4753 次点击
    这是一个创建于 2005 天前的主题,其中的信息可能已经有所发展或是发生改变。

    async/await 这个协程 异步为什么对磁盘 io 无效?

    import asyncio
    async def wr1(): # f = open('text1.txt','w') # for x in range(1,39999999): # f.write('12345ddd') # f.close()

    f = open('text3.txt','r') print(f.read()) f.close() 

    async def wr2(): # f = open('text2.txt','w') # for x in range(1,79999999): # f.write('23456fff') # f.close()

    for x in range(1,519999): print('xx') 

    async def wr3(): # f = open('text3.txt','w') # for x in range(1,99999999): # f.write('34567ggg') # f.close()

    for x in range(1,919999): print('yy') 

    def demo4():

    async def washing1(): await wr1() async def washing2(): await wr2() async def washing3(): await wr3() # 1. 创建一个事件循环 loop = asyncio.get_event_loop() # 2. 将异步函数加入事件队列 tasks = [ washing1(), washing2(), washing3(), ] # 3. 执行事件队列, 直到最晚的一个事件被处理完毕后结束 loop.run_until_complete(asyncio.wait(tasks)) # 4. 如果不再使用 loop, 建议养成良好关闭的习惯 loop.close() 

    if name == 'main': start = time()

     demo4() end = time() print('elapsed time = ' + str(end - start)) 

    第一段是读取磁盘,第二第三段是打印。按道理遇到 io,dma 交出总线,cpu 就空运转直到有数据才工作,所以 wr1 应该和 2 或 3 一块执行才对的,而实际情况不是这样的,是跟单线程同步执行一样的所需时间

    lucays
        1
    lucays  
       2020-04-15 18:21:41 +08:00
    washing1(),washing2(),washing3()不要 await wr1(),wr2(), wr3()这么搞,这样本来就和同步一样了
    lniwn
        2
    lniwn  
       2020-04-15 18:22:48 +08:00   1
    首先你得明白协程的概念,不是加个 async 修饰就能叫异步函数的。如果使用了 asyncio,那 io 以及 sleep 等操作,就要使用 asyncio 包内的封装函数。或者使用 executor 。
    你的代码里 open 操作卡死整个线程,导致没法 yield 到其他协程,所以只能顺序执行。
    CosimoZi
        3
    CosimoZi  
       2020-04-15 18:24:32 +08:00   3
    不是你说他是协程它就是协程的,它得是协程它才是一个协程.
    https://github.com/Tinche/aiofiles
    gwy15
        4
    gwy15  
       2020-04-15 18:27:00 +08:00
    在异步函数里面调用同步函数还是会阻塞的啊,你得用异步的文件接口。官方库里面没有,得用线程池,或者你自己造。
    iyaozhen
        5
    iyaozhen  
       2020-04-15 18:44:56 +08:00
    这就是 Python 这些语言半路出家搞协程的缺点

    底层很多东西没有异步,不是简单加个 async 关键字就解决问题了

    其实目前绝大部分异步方案都无法做到文件 IO 的异步,都是线程池去模拟的
    iyaozhen
        6
    iyaozhen  
       2020-04-15 18:46:26 +08:00
    janxin
        7
    janxin  
       2020-04-15 18:50:26 +08:00 via iPhone
    需要选择支持异步功能的 io 库
    fghjghf
        8
    fghjghf  
    OP
       2020-04-15 22:01:01 +08:00
    @lniwn 不懂求解。那就是说,必须是 asyncio 包内封装的函数,例如 asyncio.sleep(3)这种才有用吗?(我也测过,asyncio.sleep 函数的确有效,会快很多,但这不是真的 io 操作啊)。那遇到真的 io 操作如何是好?其实我是想和 tornado 搭配用的。tornado6 不支持 @gen.coroutine 了,必须用 async/await 。我的理解 ioloop 是通过 epoll 的 in out error 非堵塞做到单线程高并发的,遇到 EAGAIN 就用协程继续执行另一段逻辑。不知道这样理解是否有错
    Trim21
        9
    Trim21  
       2020-04-15 22:09:26 +08:00
    网络 io 有原生协程,文件 io 要要协程只能用线程包起来,没法原生异步。
    fghjghf
        10
    fghjghf  
    OP
       2020-04-15 22:36:36 +08:00
    @Trim21 不懂求解。
    from tornado.web import RequestHandler
    from tornado import gen
    import tornado.ioloop

    class IndexHandler(RequestHandler):
    def get(self):
    self.write('this is index')

    class BlockingHandler(RequestHandler):
    async def get(self):
    result = await self.dosomething()
    self.write(result)

    async def dosomething(self):
    # 如果是其他处理函数或者逻辑,要保证函数是协程
    await gen.sleep(20)
    return 'block end'

    app = tornado.web.Application([
    (r"/index", IndexHandler),
    (r"/blocking", BlockingHandler)
    ])
    if __name__ == "__main__":
    app.listen(80)
    tornado.ioloop.IOLoop.instance().start()

    那 async/await 用在 tornado6 上有啥作用呢?一定要 asyncio 内包装的函数才有效。但 IOLoop 已经用 epoll 实现网络 io 复用了。实际应用中,堵塞的不都是磁盘 io 么。那这么做的目的又是啥呢
    Trim21
        11
    Trim21  
       2020-04-15 22:47:31 +08:00
    @fghjghf #10 io 复用和异步 io 是两个概念吧,async/await 是为了解决 io 阻塞,不负责解决 io 是否复用的问题。
    fghjghf
        12
    fghjghf  
    OP
       2020-04-15 22:58:54 +08:00
    @Trim21 但网络 io 的堵塞问题,封装 eopll 的 ioloop 已经帮我们处理了。底层有个队列。socket 非堵塞执行,epollin 和 out 的时候才能寻找对应路由表执行逻辑。EAGAIN 就 modify epoll 的状态,继续执行队列的下一个,如此类推。那就是能走到路由表的 client socket 的网络 io 绝对是可用的。根本不存在堵塞啊。那 tornado 上的 async/await 具体有啥作用呢,不知道我这理解有没有错
    Trim21
        13
    Trim21  
       2020-04-15 23:19:07 +08:00
    @fghjghf #12 这个是 python 语言内的异步。之前 python 同步调用(比如 requests.get )是没法在 io 阻塞的时候让出解释器的。
    PTLin
        14
    PTLin  
       2020-04-15 23:33:36 +08:00
    lolizeppelin
        15
    lolizeppelin  
       2020-04-16 02:19:45 +08:00
    没学会走就开始跑就这结果了

    正正经经的把异步编程写几次,什么 select,epoll 多线程都好好用过几次再来折腾协程吧

    别堕落到低端 php 程序员的水准好么
    neoblackcap
        16
    neoblackcap  
       2020-04-16 03:00:36 +08:00
    async/await 本质上是对 IO 复用机制的封装,系统提供的 IO 复用不能完成的事情,async/await 也不能实现。比如你想用底层是 epoll 实现的 eventloop 去处理文件 IO 那是不行的,要不就是模拟。
    去读《 Unix 网络编程》吧,回来就会更好地理解这些语法
    dreamapple
        17
    dreamapple  
       2020-04-16 03:41:02 +08:00 via Android
    python 的异步不完备吧,现在没必要在上面浪费时间
    conn4575
        18
    conn4575  
       2020-04-16 07:28:29 +08:00 via Android
    官方 group 有讨论过这个问题,由于底层系统不支持,现在的异步本地 io 都是多线程包装的,实际的提升很小,所以 asycio 才没有做这个
    CzaOrz
        19
    CzaOrz  
       2020-04-16 08:43:57 +08:00
    --- async/await 这个协程 异步为什么对磁盘 io 无效?

    可以看看官网文档,明确说了对磁盘 IO 不支持,他们推荐 `loop.run_in_executor`
    lniwn
        20
    lniwn  
       2020-04-16 09:40:24 +08:00
    @fghjghf #8 11,16,19 楼已经回答这个问题了。
    Orenoid
        21
    Orenoid  
       2020-04-16 09:48:54 +08:00
    因为 python 的协程本质上是借助 IO 多路复用来实现异步的,磁盘 IO 没有相应的机制和接口
    fghjghf
        22
    fghjghf  
    OP
       2020-04-16 10:03:38 +08:00
    @lolizeppelin 不看我上面的回复吗?张嘴就来???
    pmispig
        23
    pmispig  
       2020-04-16 10:22:08 +08:00
    python 的协程就是搞笑的,别花太多心思,底层大部分不支持。比如网络 io,你用 socket 弄到死都不能异步,你得用
    asyncio.open_connection(host,22),
    ipwx
        24
    ipwx  
       2020-04-16 10:23:39 +08:00
    @pmispig ... asyncio.XXX 也是 socket 啊,不是 socket 库的才是 socket 啊。你这批判毫无道理啊。
    ipwx
        25
    ipwx  
       2020-04-16 10:24:13 +08:00
    @pmispig 就好像你用 java,用基础 socket 它也一样不异步呀。你得用异步框架比如 vert.x
    pmispig
        26
    pmispig  
       2020-04-16 10:27:04 +08:00
    @ipwx 看你跟什么比,你用 go 的,最基础的 net.Conn 就是支持的,python 要是不能让 socket 支持,那异步有个毛用呢,现在这么多库都是基于 socket,得要人家全部重写
    ipwx
        27
    ipwx  
       2020-04-16 10:33:22 +08:00
    @pmispig

    go 新出来了,大家要造新类库,可以这没问题。

    asyncio 新出来了,大家要造新类库,不行这很垃圾。

    不觉得这么评价很奇怪么?
    youxiachai
        28
    youxiachai  
       2020-04-16 10:35:37 +08:00   1
    为啥宁愿发帖都不看看官方文档...
    https://github.com/python/asyncio/wiki/ThirdParty#filesystem
    我一个不搞 python 都能找到答案...
    sikong31
        29
    sikong31  
       2020-04-16 11:10:54 +08:00
    这需要库专门支持,比如 requests 不行得用 aiohttp
    不像多线程,直接往里面放就行了,多线程该阻塞的还是阻塞,只不过不在一个线程
    协程是阻塞的时候直接转向 loop 里的下一个任务,所以这里面就有一个操作,就是告诉系统你待会儿来找我,
    普通的库并没有这个操作,只会让你等着
    就像买东西,有些人你能打个招呼,待会等做完了来取东西,有些只能等着不能走
    no1xsyzy
        30
    no1xsyzy  
       2020-04-16 15:09:31 +08:00
    @pmispig #26 跟 go 比异步支持那是作死,整个语言设计和运行时设计就是想着异步来的。
    你有本事跟 erlang 比分布式系统啊,go 还要 grpc,那之前用 xmlrpc 的那些是不是都得重写?
    何况这叫协程,一个不接受协调的程序放里面不能如你想象地运作,不是很符合语义吗?

    你需要的是 gevents 吧……
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3251 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 00:05 PVG 08:05 LAX 17:05 JFK 20:05
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86