是我对于协程的用法有误还是 http 请求本身就这么消耗资源

2020-06-29 19:13:59 +08:00
 just1

原有的代码是爬虫,化简完代码是这样

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%,是我对于协程有错误的理解吗,求指点

3577 次点击
所在节点    Python
21 条回复
xiaolinjia
2020-06-29 19:32:27 +08:00
你这不是 100 个。是 100 x while 循环的次数个。
arrow8899
2020-06-29 19:43:08 +08:00
不是你这么用的。。。
j0hnj
2020-06-29 19:52:38 +08:00
百度要被你干死了……
just1
2020-06-29 20:00:04 +08:00
@xiaolinjia
@arrow8899
@j0hnj 求指点...实际工作的脚本应该是从 queue 获得目标 url,这里简化写成了死循环而已
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()```
Vibra
2020-06-29 20:02:59 +08:00
@j0hnj 没有 ua 百度不会理你的
just1
2020-06-29 20:19:26 +08:00
@rimutuyuan 实际工作的脚本应该是从 queue 获得目标 url,这里简化写成了死循环而已
crella
2020-06-29 21:39:42 +08:00
如果你要爬取得网站网速快的话,那么平均每两次下载的时间间隔很小,而代码中又是 100 个 worker(),那么可以认为每两次下载时间没有空闲时间,cpu 的单核占用就是达到了 100%
just1
2020-06-29 22:18:52 +08:00
@crella #8 大概可能是这个情况,但是我的疑惑在于 http 会这么消耗 cpu 吗?运行时网络不过是大概 send340kb/s,recv900kb/s (不过小包比较多)
如果这样好像除了堆机器、开多进程,是不是没有办法优化了?
silencefly
2020-06-29 22:22:43 +08:00
如一楼的意思 是 100 个 job 一起跑 不是一个 job 跑 100 次
just1
2020-06-29 22:44:10 +08:00
@silencefly #10 就是 100 个 job 一起所以引入协程,不然一个个太慢了
tolerance
2020-06-29 22:59:09 +08:00
求教,写爬虫怎么才能不违法
linvaux
2020-06-29 23:12:58 +08:00
@tolerance 做搜索引擎,而且体量要很大的那种
imn1
2020-06-29 23:22:49 +08:00
如果用的是板载网卡,是需要 CPU 处理数据的
用那种死贵的独立网卡,可以卡内处理数据,省点 CPU
msg7086
2020-06-30 03:30:05 +08:00
这也不是 HTTP 啊,这明明是 HTTPS 啊,初始化 TLS 秘钥交换多次握手不要钱的啊……
leer
2020-06-30 07:45:36 +08:00
@tolerance 自己研究不违法,遵守爬虫协议
lpts007
2020-06-30 09:47:37 +08:00
@just1 你知道 while 1 的意思吗 死循环内异步 单核满载不是意料之中吗,跟 http 协议有什么关系?
再说你实际业务生产待爬 url 的速度 也不可能就是 while 1 吧。
注意点别人网站的承受能力,别一不小心搞成攻击了。
BingoXuan
2020-06-30 10:04:03 +08:00
https 需要消耗一定 cpu 资源去加解密的,而且你写的是 100x 的死循环请求。假如你一秒单线程能完成 10 次,那么实际就是 1000 次请求了。

你需要去掉 while 循环,通过 asyncio 创建 size 为 100 的 queue,不断从 queue 中获取任务,通过 futures 来设置 result 或者 error
yzk66880
2020-06-30 18:09:49 +08:00
你这 while 1 。。。
just1
2020-06-30 20:01:54 +08:00
@yzk66880 #19 怎么都不看题啊

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/685712

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX