想用 Python 做一个后台扫描工具
仿照 asyncio 官网的生产者消费者模式写了一个 demo
发现运行到一半会阻塞住(有时会,有时不会?)
但我看着貌似不会卡住啊
求大佬救救孩子
1
Ritter OP 对了
生产者是从本地文件夹读取字典文件 消费者拼接 url 发起请求 |
2
Ritter OP 难受
|
3
cz5424 2020-01-19 15:08:33 +08:00 via iPhone
你贴代码吧这样描述没人能解答
|
6
Ritter OP |
7
chenqh 2020-01-19 15:15:47 +08:00 1
你的日志也太少了把!!
put 的日志打印一些? |
8
ipwx 2020-01-19 15:16:48 +08:00 1
大哥 readFromFolder 是阻塞的,你在 async def put 里面得用线程池去执行它。asyncio 的主线程是单线程,没法执行这种阻塞函数。
https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor |
9
ipwx 2020-01-19 15:17:09 +08:00
顺便吐槽一句楼上,这么明显的问题不是一眼就能看出来么
|
11
ipwx 2020-01-19 15:17:50 +08:00
除了 readFromFolder, f.read() 也是阻塞的,也得放在 executor 里面
|
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 强行进入后台运行状态才对吧? |
15
ipwx 2020-01-19 15:26:06 +08:00
顺便 loop.create_task 就不用 await 了
|
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." |
20
youngce 2020-01-19 15:33:09 +08:00
赞同 ipwx,楼主你也要明白,目前 python 协程面临最大的问题的绝大多数第三方库均是同步的,不能支持协程异步。虽然现在已经与很多库在努力的兼容协程,但是在协程处理 io 库时,一定要请楚是否支持。不支持协程的 io 都要通过线程池来处理。官网也给出了 asyncio 中线程池的用法,可以再看看
|
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) |
28
freshgoose 2020-01-19 15:44:17 +08:00
看来 py 的协程还是很多坑啊……这么说现阶段还是用 golang 写并发比较好?
|
30
Vegetable 2020-01-19 15:45:12 +08:00
@ipwx #8 并不是无法执行阻塞,只是会阻塞 eventloop 而已。这地方不会卡死。这个方法内部的操作也并不是耗时操作。
|
31
Vegetable 2020-01-19 15:47:13 +08:00 1
你这个程序由于 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-01-19 15:53:09 +08:00
有个库叫做 aiofile,你的文件读取是阻塞的
|
35
chenqh 2020-01-19 15:55:34 +08:00
@Ritter 我一般不是这么退出的, 我一般是再 producer 那边放入特殊的字符串,比如"__end__",然后 consumer 那边接受处理,自己退出的, 你试一试?
|
37
jyyx 2020-01-19 15:58:53 +08:00 2
消费者那里抛异常, self.q.task_done 并没有执行
加 try finally 试下 |
38
Vegetable 2020-01-19 16:03:01 +08:00
#37 jyyx 说的对,报异常会导致任务消费出问题,join()那里会卡住。
|
40
Ritter OP @chenqh https://asyncio.readthedocs.io/en/latest/producer_consumer.html 官网第一个例子应该是你说的这种处理方式 我之前试过貌似也会卡住
|
43
ipwx 2020-01-19 16:18:19 +08:00
|
45
pmispig 2020-01-19 16:38:37 +08:00
请问这是什么字体,看着真舒服
|
46
Ritter OP |
47
chenqh 2020-01-19 16:39:18 +08:00
log 呀
|
50
Ritter OP |
51
hehe12dyo 2020-01-19 17:21:01 +08:00
朋友 建议你一边读一边把数据往队列里面丢。这样在读大文件读时候看起来好些。
不然一个 10m 的字典,想想就刺激。 其实这工具我写过。。 |
53
Ritter OP @hehe12dyo 一边读一边写我也想过 但是自带的 open 是阻塞的 上面有位大佬说的 aiofile 有空会去研究一下
|
54
p0wd3rop 2020-01-19 17:54:52 +08:00
这种扫描小工具建议用 Go 写,快,容易理解,很香。
|
55
KaynW 2020-01-20 12:15:40 +08:00
go
go go |