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

1
Ritter OP 对了
生产者是从本地文件夹读取字典文件 消费者拼接 url 发起请求 |
2
Ritter OP 难受
|
3
cz5424 2020 年 1 月 19 日 via iPhone
你贴代码吧这样描述没人能解答
|
6
Ritter OP |
7
simple2025 2020 年 1 月 19 日 你的日志也太少了把!!
put 的日志打印一些? |
8
ipwx 2020 年 1 月 19 日 大哥 readFromFolder 是阻塞的,你在 async def put 里面得用线程池去执行它。asyncio 的主线程是单线程,没法执行这种阻塞函数。
https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor |
9
ipwx 2020 年 1 月 19 日
顺便吐槽一句楼上,这么明显的问题不是一眼就能看出来么
|
11
ipwx 2020 年 1 月 19 日
除了 readFromFolder, f.read() 也是阻塞的,也得放在 executor 里面
|
14
ipwx 2020 年 1 月 19 日
=== 我发现楼主还有个问题,在 async def run 里面。
他只创建了 consumer = asyncio.gather(...),但是没有勒令 consumer 进入执行啊?按照道理 asyncio.gather 并不具有执行一个 coroutine 的特性啊,只有 await 才能保证让一个 coroutine 进入运行状态啊? 楼主你得用 loop.create_task 把一个 coroutine 强行进入后台运行状态才对吧? |
15
ipwx 2020 年 1 月 19 日
顺便 loop.create_task 就不用 await 了
|
18
simple2025 2020 年 1 月 19 日
@Ritter 日志,日志呢?
|
19
ipwx 2020 年 1 月 19 日
@Ritter 好吧我看了一眼文档,它当真会自动把 coroutine 变成 Task 给 schedule 起来。
"If any awaitable in aws is a coroutine, it is automatically scheduled as a Task." |
20
ynkkdev 2020 年 1 月 19 日
赞同 ipwx,楼主你也要明白,目前 python 协程面临最大的问题的绝大多数第三方库均是同步的,不能支持协程异步。虽然现在已经与很多库在努力的兼容协程,但是在协程处理 io 库时,一定要请楚是否支持。不支持协程的 io 都要通过线程池来处理。官网也给出了 asyncio 中线程池的用法,可以再看看
|
25
simple2025 2020 年 1 月 19 日
@Ritter 先把日志打出来呀
|
26
simple2025 2020 年 1 月 19 日
@Ritter 我怀疑你 put 跑完了,但是 consumer 还是卡在哪里
|
27
ipwx 2020 年 1 月 19 日
@Ritter run_in_executor 本来就是把一个阻塞函数扔到别的线程里面执行,然后把结果拿出来的。
def fn(): ....something to do await loop.run_in_executor(fn) |
28
freshgoose 2020 年 1 月 19 日
看来 py 的协程还是很多坑啊……这么说现阶段还是用 golang 写并发比较好?
|
31
Vegetable 2020 年 1 月 19 日 你这个程序由于 crawl 是不会主动跳出的,所以当任务执行完毕之后,所有 await queue.get 都会阻塞,等待新的任务入队,是卡在这里吗?
|
32
Ritter OP @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 取消了 |
33
BBrother 2020 年 1 月 19 日
有个库叫做 aiofile,你的文件读取是阻塞的
|
35
simple2025 2020 年 1 月 19 日
@Ritter 我一般不是这么退出的, 我一般是再 producer 那边放入特殊的字符串,比如"__end__",然后 consumer 那边接受处理,自己退出的, 你试一试?
|
36
simple2025 2020 年 1 月 19 日
@Ritter 你这个就是 consumer 的退出问题,导致的
|
37
jyyx 2020 年 1 月 19 日 消费者那里抛异常, self.q.task_done 并没有执行
加 try finally 试下 |
38
Vegetable 2020 年 1 月 19 日
#37 jyyx 说的对,报异常会导致任务消费出问题,join()那里会卡住。
|
40
Ritter OP @chenqh https://asyncio.readthedocs.io/en/latest/producer_consumer.html 官网第一个例子应该是你说的这种处理方式 我之前试过貌似也会卡住
|
43
ipwx 2020 年 1 月 19 日
|
45
pmispig 2020 年 1 月 19 日
请问这是什么字体,看着真舒服
|
46
Ritter OP |
47
simple2025 2020 年 1 月 19 日
log 呀
|
50
Ritter OP |
51
hehe12dyo 2020 年 1 月 19 日
朋友 建议你一边读一边把数据往队列里面丢。这样在读大文件读时候看起来好些。
不然一个 10m 的字典,想想就刺激。 其实这工具我写过。。 |
54
p0wd3rop 2020 年 1 月 19 日
这种扫描小工具建议用 Go 写,快,容易理解,很香。
|
55
KaynW 2020 年 1 月 20 日
go
go go |