原有的代码是爬虫,化简完代码是这样
import asyncio
import aiohttp
async def worker():
while 1:
try:
async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=5)) as session:
async with session.post('https://www.baidu.com') as r:
_ = await r.text()
except RuntimeError:
break
async def main():
await asyncio.wait([worker() for _ in range(100)])
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
只需要不到 100 个协程,cpu 单核就可以 100%,是我对于协程有错误的理解吗,求指点
1
xiaolinjia 2020-06-29 19:32:27 +08:00
你这不是 100 个。是 100 x while 循环的次数个。
|
2
arrow8899 2020-06-29 19:43:08 +08:00
不是你这么用的。。。
|
3
j0hnj 2020-06-29 19:52:38 +08:00 1
百度要被你干死了……
|
4
just1 OP |
5
rimutuyuan 2020-06-29 20:02:47 +08:00
```import asyncio
import aiohttp async def worker(url): try: async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=5)) as session: async with session.post(url) as r: _ = await r.text() except RuntimeError: break async def main(): urls = ["https://baidu.com", "https://baidu.com"] await asyncio.wait([worker(url) for url in range(urls)]) if __name__ == '__main__': loop = asyncio.get_event_loop() loop.run_until_complete(main()) loop.close()``` |
7
just1 OP @rimutuyuan 实际工作的脚本应该是从 queue 获得目标 url,这里简化写成了死循环而已
|
8
crella 2020-06-29 21:39:42 +08:00 1
如果你要爬取得网站网速快的话,那么平均每两次下载的时间间隔很小,而代码中又是 100 个 worker(),那么可以认为每两次下载时间没有空闲时间,cpu 的单核占用就是达到了 100%
|
9
just1 OP @crella #8 大概可能是这个情况,但是我的疑惑在于 http 会这么消耗 cpu 吗?运行时网络不过是大概 send340kb/s,recv900kb/s (不过小包比较多)
如果这样好像除了堆机器、开多进程,是不是没有办法优化了? |
10
silencefly 2020-06-29 22:22:43 +08:00 via iPhone
如一楼的意思 是 100 个 job 一起跑 不是一个 job 跑 100 次
|
11
just1 OP @silencefly #10 就是 100 个 job 一起所以引入协程,不然一个个太慢了
|
12
tolerance 2020-06-29 22:59:09 +08:00
求教,写爬虫怎么才能不违法
|
14
imn1 2020-06-29 23:22:49 +08:00
如果用的是板载网卡,是需要 CPU 处理数据的
用那种死贵的独立网卡,可以卡内处理数据,省点 CPU |
15
msg7086 2020-06-30 03:30:05 +08:00 1
这也不是 HTTP 啊,这明明是 HTTPS 啊,初始化 TLS 秘钥交换多次握手不要钱的啊……
|
17
lpts007 2020-06-30 09:47:37 +08:00
@just1 你知道 while 1 的意思吗 死循环内异步 单核满载不是意料之中吗,跟 http 协议有什么关系?
再说你实际业务生产待爬 url 的速度 也不可能就是 while 1 吧。 注意点别人网站的承受能力,别一不小心搞成攻击了。 |
18
BingoXuan 2020-06-30 10:04:03 +08:00 2
https 需要消耗一定 cpu 资源去加解密的,而且你写的是 100x 的死循环请求。假如你一秒单线程能完成 10 次,那么实际就是 1000 次请求了。
你需要去掉 while 循环,通过 asyncio 创建 size 为 100 的 queue,不断从 queue 中获取任务,通过 futures 来设置 result 或者 error |
19
yzk66880 2020-06-30 18:09:49 +08:00
你这 while 1 。。。
|
21
yucongo 2020-07-02 11:12:33 +08:00
网上有个 limited_as_completed ( asyncioplus )包,或许适应你要做的。limited_as_completed 的原始作者试过建议将 limited_as_completed 作为 asyncio 的内置标准函数,但好像不成功。
|