大佬们 我这协程写的有毛病吗? - 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
Ritter
V2EX    Python

大佬们 我这协程写的有毛病吗?

  •  
  •   Ritter 2020-01-19 14:39:27 +08:00 7382 次点击
    这是一个创建于 2140 天前的主题,其中的信息可能已经有所发展或是发生改变。

    想用 Python 做一个后台扫描工具
    仿照 asyncio 官网的生产者消费者模式写了一个 demo
    发现运行到一半会阻塞住(有时会,有时不会?)
    但我看着貌似不会卡住啊
    求大佬救救孩子

    55 条回复    2020-01-20 12:15:40 +08:00
    Ritter
        1
    Ritter  
    OP
       2020-0119 14:41:35 +08:00
    对了
    生产者是从本地文件夹读取字典文件
    消费者拼接 url 发起请求
    Ritter
        2
    Ritter  
    OP
       2020-01-19 14:52:05 +08:00
    难受
    cz5424
        3
    cz5424  
       2020-01-19 15:08:33 +08:00 via iPhone
    你贴代码吧这样描述没人能解答
    Ritter
        4
    Ritter  
    OP
       2020-01-19 15:10:04 +08:00
    @cz5424 大佬上面有代码
    cz5424
        5
    cz5424  
       2020-01-19 15:12:41 +08:00 via iPhone
    @Ritter 阻塞的时候中断看看阻塞在哪个语句
    Ritter
        6
    Ritter  
    OP
       2020-01-19 15:14:09 +08:00
    simple2025
        7
    simple2025  
       2020-01-19 15:15:47 +08:00   1
    你的日志也太少了把!!
    put 的日志打印一些?
    ipwx
        8
    ipwx  
       2020-01-19 15:16:48 +08:00   1
    大哥 readFromFolder 是阻塞的,你在 async def put 里面得用线程池去执行它。asyncio 的主线程是单线程,没法执行这种阻塞函数。

    https://docs.python.org/3/library/asyncio-evenloop.html#asyncio.loop.run_in_executor
    ipwx
        9
    ipwx  
       2020-01-19 15:17:09 +08:00
    顺便吐槽一句楼上,这么明显的问题不是一眼就能看出来么
    Ritter
        10
    Ritter  
    OP
       2020-01-19 15:17:36 +08:00
    @cz5424 Ctrl C 中断不了
    ipwx
        11
    ipwx  
       2020-01-19 15:17:50 +08:00
    除了 readFromFolder, f.read() 也是阻塞的,也得放在 executor 里面
    Ritter
        12
    Ritter  
    OP
       2020-01-19 15:20:11 +08:00
    @ipwx 可是他是执行到一半的时候阻塞了 self.q.put()这句代码是可以执行到的
    ipwx
        13
    ipwx  
       2020-01-19 15:22:54 +08:00
    @Ritter 楼主也没放日志(差评)。

    不过 async def put 这个函数问题太大了,怎么都会出问题的。
    ipwx
        14
    ipwx  
       2020-01-19 15:25:46 +08:00
    === 我发现楼主还有个问题,在 async def run 里面。

    他只创建了 cOnsumer= asyncio.gather(...),但是没有勒令 consumer 进入执行啊?按照道理 asyncio.gather 并不具有执行一个 coroutine 的特性啊,只有 await 才能保证让一个 coroutine 进入运行状态啊?

    楼主你得用 loop.create_task 把一个 coroutine 强行进入后台运行状态才对吧?
    ipwx
        15
    ipwx  
       2020-01-19 15:26:06 +08:00
    顺便 loop.create_task 就不用 await 了
    Ritter
        16
    Ritter  
    OP
       2020-01-19 15:27:47 +08:00
    @ipwx 代码都是官网抄的 怎么会出错我也不知道啊(狗头)
    Ritter
        17
    Ritter  
    OP
       2020-01-19 15:28:16 +08:00
    @ipwx asyncio.gather 之后确实是会运行的 我试过了
    simple2025
        18
    simple2025  
       2020-01-19 15:29:19 +08:00
    @Ritter 日志,日志呢?
    ipwx
        19
    ipwx  
       2020-01-19 15:31:30 +08:00
    @Ritter 好吧我看了一眼文档,它当真会自动把 coroutine 变成 Task 给 schedule 起来。

    "If any awaitable in aws is a coroutine, it is automatically scheduled as a Task."
    ynkkdev
        20
    ynkkdev  
       2020-01-19 15:33:09 +08:00
    赞同 ipwx,楼主你也要明白,目前 python 协程面临最大的问题的绝大多数第三方库均是同步的,不能支持协程异步。虽然现在已经与很多库在努力的兼容协程,但是在协程处理 io 库时,一定要请楚是否支持。不支持协程的 io 都要通过线程池来处理。官网也给出了 asyncio 中线程池的用法,可以再看看
    Ritter
        21
    Ritter  
    OP
       2020-01-19 15:34:23 +08:00
    @chenqh 大佬 我打印了一下 貌似是在 self.q.get()这卡住了
    Ritter
        22
    Ritter  
    OP
       2020-01-19 15:35:36 +08:00
    @youngce 请求库是 aiohttp 异步的 意思是 读取文件那里卡住了吗
    Ritter
        23
    Ritter  
    OP
       2020-01-19 15:36:08 +08:00
    @ipwx 大佬 asyncio 的队列能跨线程使用吗
    Ritter
        24
    Ritter  
    OP
       2020-01-19 15:36:36 +08:00
    @chenqh put 这个函数是可以运行完的
    simple2025
        25
    simple2025  
       2020-01-19 15:40:09 +08:00
    @Ritter 先把日志打出来呀
    simple2025
        26
    simple2025  
       2020-01-19 15:40:46 +08:00
    @Ritter 我怀疑你 put 跑完了,但是 consumer 还是卡在哪里
    ipwx
        27
    ipwx  
       2020-01-19 15:41:01 +08:00
    @Ritter run_in_executor 本来就是把一个阻塞函数扔到别的线程里面执行,然后把结果拿出来的。

    def fn():
    ....something to do

    await loop.run_in_executor(fn)
    freshgoose
        28
    freshgoose  
       2020-01-19 15:44:17 +08:00
    看来 py 的协程还是很多坑啊……这么说现阶段还是用 golang 写并发比较好?
    Ritter
        29
    Ritter  
    OP
       2020-01-19 15:44:19 +08:00
    @chenqh 好像是 但是我后面一句已经把 consumer 取消了
    Vegetable
        30
    Vegetable  
       2020-01-19 15:45:12 +08:00
    @ipwx #8 并不是无法执行阻塞,只是会阻塞 eventloop 而已。这地方不会卡死。这个方法内部的操作也并不是耗时操作。
    Vegetable
        31
    Vegetable  
       2020-01-19 15:47:13 +08:00   1
    你这个程序由于 crawl 是不会主动跳出的,所以当任务执行完毕之后,所有 await queue.get 都会阻塞,等待新的任务入队,是卡在这里吗?
    Ritter
        32
    Ritter  
    OP
       2020-01-19 15:49:39 +08:00
    @Vegetable
    async def run(self):
    crawls = [self.crawl(i) for i in range(self.max_concurrency)]
    cOnsumer= asyncio.gather(*crawls)
    ...
    # cancel consumer
    consumer.cancel()

    我这里已经把 consumer 取消了
    BBrother
        33
    BBrother  
       2020-01-19 15:53:09 +08:00
    有个库叫做 aiofile,你的文件读取是阻塞的
    Ritter
        34
    Ritter  
    OP
       2020-01-19 15:55:24 +08:00
    @BBrother 可是 put 函数是可以完整运行完的 这里是运行到一半的时候卡住了
    simple2025
        35
    simple2025  
       2020-01-19 15:55:34 +08:00
    @Ritter 我一般不是这么退出的, 我一般是再 producer 那边放入特殊的字符串,比如"__end__",然后 consumer 那边接受处理,自己退出的, 你试一试?
    simple2025
        36
    simple2025  
       2020-01-19 15:56:37 +08:00
    @Ritter 你这个就是 consumer 的退出问题,导致的
    jyyx
        37
    jyyx  
       2020-01-19 15:58:53 +08:00   2
    消费者那里抛异常, self.q.task_done 并没有执行
    加 try finally 试下
    Vegetable
        38
    Vegetable  
       2020-01-19 16:03:01 +08:00
    #37 jyyx 说的对,报异常会导致任务消费出问题,join()那里会卡住。
    BBrother
        39
    BBrother  
       2020-01-19 16:06:51 +08:00
    @Ritter 你的卡住是指程序运行到一半不动了,并且没有输出,也没有执行完,而且还是概率触发?
    Ritter
        40
    Ritter  
    OP
       2020-01-19 16:15:23 +08:00
    @chenqh https://asyncio.readthedocs.io/en/latest/producer_consumer.html 官网第一个例子应该是你说的这种处理方式 我之前试过貌似也会卡住
    Ritter
        41
    Ritter  
    OP
       2020-01-19 16:15:52 +08:00
    @jyyx
    @Vegetable 可是异常不会向上传播吗?
    Ritter
        42
    Ritter  
    OP
       2020-01-19 16:18:04 +08:00
    @BBrother 输出是有输出的 就是有概率会阻塞
    ipwx
        43
    ipwx  
       2020-01-19 16:18:19 +08:00
    @Ritter 异常无论是不是向上传播,q.task_done 都不能执行了呀,然后 join() 一定会卡住啊。。。

    try:
    ...
    finally:
    q.task_done()
    Vegetable
        44
    Vegetable  
       2020-01-19 16:28:09 +08:00
    @Ritter 因为你没有直接 await crawl,所以这个异常应该是不会传播的。程序不会因此退出
    pmispig
        45
    pmispig  
       2020-01-19 16:38:37 +08:00
    请问这是什么字体,看着真舒服
    Ritter
        46
    Ritter  
    OP
       2020-01-19 16:39:06 +08:00
    @jyyx
    @Vegetable
    @ipwx
    是报异常了 原因也是因为异常导致 put 的数量和 task_done 不一致
    学到了 感谢各位大佬的鼎力相助
    谢谢谢谢~~
    simple2025
        47
    simple2025  
       2020-01-19 16:39:18 +08:00
    log 呀
    Ritter
        48
    Ritter  
    OP
       2020-01-19 16:41:38 +08:00   1
    @pmispig 这是 carbon 网站生成的图片 样式用的是 VScode 的
    Ritter
        49
    Ritter  
    OP
       2020-01-19 16:42:02 +08:00
    @chenqh 已经解决了 大佬 感谢回复
    Ritter
        50
    Ritter  
    OP
       2020-01-19 16:43:35 +08:00
    hehe12dyo
        51
    hehe12dyo  
       2020-01-19 17:21:01 +08:00
    朋友 建议你一边读一边把数据往队列里面丢。这样在读大文件读时候看起来好些。
    不然一个 10m 的字典,想想就刺激。
    其实这工具我写过。。
    cz5424
        52
    cz5424  
       2020-01-19 17:24:31 +08:00 via iPhone
    @ipwx 楼上根本就没看代码,手动狗头
    Ritter
        53
    Ritter  
    OP
       2020-01-19 17:27:17 +08:00
    @hehe12dyo 一边读一边写我也想过 但是自带的 open 是阻塞的 上面有位大佬说的 aiofile 有空会去研究一下
    p0wd3rop
        54
    p0wd3rop  
       2020-01-19 17:54:52 +08:00
    这种扫描小工具建议用 Go 写,快,容易理解,很香。
    KaynW
        55
    KaynW  
       2020-01-20 12:15:40 +08:00
    go
    go
    go
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     4457 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 09:57 PVG 17:57 LAX 01:57 JFK 04:57
    Do have faith in what you're doing.
    ubao msn 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