文章目录
- 1.协程:在单线程内实现并发
- 2.通过信号量控制并发度
1.协程:在单线程内实现并发
- 单线程爬虫的执行路径
- 协程:在单线程内实现并发
核心原理:用一个超级循环(其实就是while true)循环
核心原理:配合IO多路复用原理(IO时CPU可以干其他事情),等待IO时,切换到下一个
CPU - Python 异步IO库介绍:asyncio
注意:
(1)要用在异步IO编程中
依赖的库必须支持异步IO特性
(2)爬虫引用中:
requests 不支持异步
需要用 aiohttp
import asyncio
# 获取事件循环
loop = asyncio.get_event_loop()##就是 while True:
# 定义协程
async def myfunc(url):
await get_url(url)## await目的是IO不进行阻塞,而是让程序进行
下一个loop
# 创建task列表
##对多个url进行并发执行
tasks = [loop.create_task(myfunc(url)) for url in urls]
# 执行爬虫事件列表
loop.run_until_complete(asyncio.wait(tasks))##执行tasks,等待tasks完成
- eg:08. async_spider.py
import asyncio
import aiohttp
import blog_spider
##协程:在超级循环里可以跑的函数,就是在异步IO中执行async_craw函数
async def async_craw(url):
print("craw url: ", url)
##async with创建对象
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
##resp.text()获取结果
result = await resp.text()
print(f"craw url: {url}, {len(result)}")
##超级循环
loop = asyncio.get_event_loop()
##使用协程函数定义一个list
tasks = [
loop.create_task(async_craw(url))
for url in blog_spider.urls]
import time
start = time.time()
##等待tasks完成
loop.run_until_complete(asyncio.wait(tasks))
end = time.time()
print("use time seconds: ", end - start)
- 测试:
2.通过信号量控制并发度
- 信号量(英语:Semaphore)
信号量(英语:Semaphore)又称为信号量、旗语
是一个同步对象,用于保持在0至指定最大值之间的一个计数值。
当线程完成一次对该semaphore对象的等待(wait)时,该计数值减一;
当线程完成一次对semaphore对象的释放(release)时,计数值加一。
当计数值为0,则线程等待该semaphore对象不再能成功直至该semaphore对象变成signaled状态
semaphore对象的计数值大于0,为signaled状态;计数值等于0,为nonsignaled状态. - 语法
方法1:
##10就是并发量的意思
sem = asyncio.Semaphore(10)
# ... later
async with sem:
# work with shared resource
方法2:
sem = asyncio.Semaphore(10)
# ... later
await sem.acquire()
try:
# work with shared resource
finally:
sem.release()
- eg:
import asyncio
import aiohttp
import blog_spider
##并发度10
semaphore = asyncio.Semaphore(10)
async def async_craw(url):
async with semaphore:
print("craw url: ", url)
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
result = await resp.text()
await asyncio.sleep(5)
print(f"craw url: {url}, {len(result)}")
loop = asyncio.get_event_loop()
tasks = [
loop.create_task(async_craw(url))
for url in blog_spider.urls]
import time
start = time.time()
loop.run_until_complete(asyncio.wait(tasks))
end = time.time()
print("use time seconds: ", end - start)
- 测试:10个10个进行爬取
- 参考:链接