原有的代码是爬虫,化简完代码是这样
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 ![]() 百度要被你干死了…… |
![]() | 4 just1 OP |
5 14v45mJPBYJW8dT7 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 ![]() 如果你要爬取得网站网速快的话,那么平均每两次下载的时间间隔很小,而代码中又是 100 个 worker(),那么可以认为每两次下载时间没有空闲时间,cpu 的单核占用就是达到了 100% |
![]() | 9 just1 OP @crella #8 大概可能是这个情况,但是我的疑惑在于 http 会这么消耗 cpu 吗?运行时网络不过是大概 send340kb/s,recv900kb/s (不过小包比较多) 如果这样好像除了堆机器、开多进程,是不是没有办法优化了? |
![]() | 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 ![]() 这也不是 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 ![]() 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 的内置标准函数,但好像不成功。 |