跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • 大佬们 我这协程写的有毛病吗?
未分類
27 3 月 2020

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

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

資深大佬 : Ritter 63

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

大佬有話說 (55)

  • 主 資深大佬 : Ritter

    对了
    生产者是从本地文件夹读取字典文件
    消费者拼接 url 发起请求

  • 主 資深大佬 : Ritter

    难受

  • 資深大佬 : cz5424

    你贴代码吧这样描述没人能解答

  • 主 資深大佬 : Ritter

    @cz5424 大佬上面有代码

  • 資深大佬 : cz5424

    @Ritter 阻塞的时候中断看看阻塞在哪个语句

  • 主 資深大佬 : Ritter

    ![]( https://pic.downk.cc/item/5e2401aa2fb38b8c3c73a0ca.png)
    这是调用代码

  • 資深大佬 : chenqh

    你的日志也太少了把!!
    put 的日志打印一些?

  • 資深大佬 : ipwx

    大哥 readFromFolder 是阻塞的,你在 async def put 里面得用线程池去执行它。asyncio 的主线程是单线程,没法执行这种阻塞函数。

    https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor

  • 資深大佬 : ipwx

    顺便吐槽一句上,这么明显的问题不是一眼就能看出来么

  • 主 資深大佬 : Ritter

    @cz5424 Ctrl C 中断不了

  • 資深大佬 : ipwx

    除了 readFromFolder, f.read() 也是阻塞的,也得放在 executor 里面

  • 主 資深大佬 : Ritter

    @ipwx 可是他是执行到一半的时候阻塞了 self.q.put()这句代码是可以执行到的

  • 資深大佬 : ipwx

    @Ritter 主也没放日志(差评)。

    不过 async def put 这个函数问题太大了,怎么都会出问题的。

  • 資深大佬 : ipwx

    === 我发现主还有个问题,在 async def run 里面。

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

    主你得用 loop.create_task 把一个 coroutine 强行进入后台运行状态才对吧?

  • 資深大佬 : ipwx

    顺便 loop.create_task 就不用 await 了

  • 主 資深大佬 : Ritter

    @ipwx 代码都是官网抄的 怎么会出错我也不知道啊(狗头)

  • 主 資深大佬 : Ritter

    @ipwx asyncio.gather 之后确实是会运行的 我试过了

  • 資深大佬 : chenqh

    @Ritter 日志,日志呢?

  • 資深大佬 : ipwx

    @Ritter 好吧我看了一眼文档,它当真会自动把 coroutine 变成 Task 给 schedule 起来。

    “If any awaitable in aws is a coroutine, it is automatically scheduled as a Task.”

  • 資深大佬 : youngce

    赞同 ipwx,主你也要明白,目前 python 协程面临最大的问题的绝大多数第三方库均是同步的,不能支持协程异步。虽然现在已经与很多库在努力的兼容协程,但是在协程处理 io 库时,一定要请楚是否支持。不支持协程的 io 都要通过线程池来处理。官网也给出了 asyncio 中线程池的用法,可以再看看

  • 主 資深大佬 : Ritter

    @chenqh 大佬 我打印了一下 貌似是在 self.q.get()这卡住了

  • 主 資深大佬 : Ritter

    @youngce 请求库是 aiohttp 异步的 意思是 读取文件那里卡住了吗

  • 主 資深大佬 : Ritter

    @ipwx 大佬 asyncio 的队列能跨线程使用吗

  • 主 資深大佬 : Ritter

    @chenqh put 这个函数是可以运行完的

  • 資深大佬 : chenqh

    @Ritter 先把日志打出来呀

  • 資深大佬 : chenqh

    @Ritter 我怀疑你 put 跑完了,但是 consumer 还是卡在哪里

  • 資深大佬 : ipwx

    @Ritter run_in_executor 本来就是把一个阻塞函数扔到别的线程里面执行,然后把结果拿出来的。

    def fn():
    ….something to do

    await loop.run_in_executor(fn)

  • 資深大佬 : freshgoose

    看来 py 的协程还是很多坑啊……这么说现阶段还是用 golang 写并发比较好?

  • 主 資深大佬 : Ritter

    @chenqh 好像是 但是我后面一句已经把 consumer 取消了

  • 資深大佬 : Vegetable

    @ipwx #8 并不是无法执行阻塞,只是会阻塞 eventloop 而已。这地方不会卡死。这个方法内部的操作也并不是耗时操作。

  • 資深大佬 : Vegetable

    你这个程序由于 crawl 是不会主动跳出的,所以当任务执行完毕之后,所有 await queue.get 都会阻塞,等待新的任务入队,是卡在这里吗?

  • 主 資深大佬 : Ritter

    @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

    有个库叫做 aiofile,你的文件读取是阻塞的

  • 主 資深大佬 : Ritter

    @BBrother 可是 put 函数是可以完整运行完的 这里是运行到一半的时候卡住了

  • 資深大佬 : chenqh

    @Ritter 我一般不是这么退出的, 我一般是再 producer 那边放入特殊的字符串,比如”__end__”,然后 consumer 那边接受处理,自己退出的, 你试一试?

  • 資深大佬 : chenqh

    @Ritter 你这个就是 consumer 的退出问题,导致的

  • 資深大佬 : jyyx

    消费者那里抛异常, self.q.task_done 并没有执行
    加 try finally 试下

  • 資深大佬 : Vegetable

    #37 jyyx 说的对,报异常会导致任务消费出问题,join()那里会卡住。

  • 資深大佬 : BBrother

    @Ritter 你的卡住是指程序运行到一半不动了,并且没有输出,也没有执行完,而且还是概率触发?

  • 主 資深大佬 : Ritter

    @chenqh https://asyncio.readthedocs.io/en/latest/producer_consumer.html 官网第一个例子应该是你说的这种处理方式 我之前试过貌似也会卡住

  • 主 資深大佬 : Ritter

    @jyyx
    @Vegetable 可是异常不会向上传播吗?

  • 主 資深大佬 : Ritter

    @BBrother 输出是有输出的 就是有概率会阻塞

  • 資深大佬 : ipwx

    @Ritter 异常无论是不是向上传播,q.task_done 都不能执行了呀,然后 join() 一定会卡住啊。。。

    try:
    …
    finally:
    q.task_done()

  • 資深大佬 : Vegetable

    @Ritter 因为你没有直接 await crawl,所以这个异常应该是不会传播的。程序不会因此退出

  • 資深大佬 : pmispig

    请问这是什么字体,看着真舒服

  • 主 資深大佬 : Ritter

    @jyyx
    @Vegetable
    @ipwx
    是报异常了 原因也是因为异常导致 put 的数量和 task_done 不一致
    学到了 感谢各位大佬的鼎力相助
    谢谢谢谢~~

  • 資深大佬 : chenqh

    log 呀

  • 主 資深大佬 : Ritter

    @pmispig 这是 carbon 网站生成的图片 样式用的是 VScode 的

  • 主 資深大佬 : Ritter

    @chenqh 已经解决了 大佬 感谢回复

  • 主 資深大佬 : Ritter

    @pmispig https://carbon.now.sh/

  • 資深大佬 : hehe12dyo

    朋友 建议你一边读一边把数据往队列里面丢。这样在读大文件读时候看起来好些。
    不然一个 10m 的字典,想想就刺激。
    其实这工具我写过。。

  • 資深大佬 : cz5424

    @ipwx 上根本就没看代码,手动狗头

  • 主 資深大佬 : Ritter

    @hehe12dyo 一边读一边写我也想过 但是自带的 open 是阻塞的 上面有位大佬说的 aiofile 有空会去研究一下

  • 資深大佬 : p0wd3rop

    这种扫描小工具建议用 Go 写,快,容易理解,很香。

  • 資深大佬 : KaynW

    go
    go
    go

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具