1-Python - asyncio
about
asyncio
是Python原生的底层协程模块。
应用于爬虫和webserver框架的底层。
对asyncio
有所了解,有助于加深对协程的理解。
开启一个协程任务
import asyncio
async def func(): # 协程函数
print('start...')
await asyncio.sleep(1) # 阻塞
print('end....')
loop = asyncio.get_event_loop() # 开启事件循环
loop.run_until_complete(func())
上例是使用asyncio实现协程任务的标准示例。
需要补充的是:
async
声明一个协程函数。await
是其阻塞作用,协程函数要从这里切换出去,还能保证再切回来。另外,await
必须写在async
函数中。loop
是事件循环,所有的协程的执行、调度都离不开这个loop
。
开启多个协程任务
启动多个任务,无返回值
import asyncio
async def func():
print('start...')
await asyncio.sleep(1)
print('end....')
loop = asyncio.get_event_loop()
waite_obj = asyncio.wait([func(), func(), func(), func(), func()])
loop.run_until_complete(waite_obj)
'''
start...
start...
start...
start...
start...
end....
end....
end....
end....
end....
'''
上例是使用asyncio实现多个协程任务的示例。
启动多个任务,无返回值
import asyncio
async def func():
print('start...')
await asyncio.sleep(1)
print('end....')
return 123
# 写法1
loop = asyncio.get_event_loop()
t1 = loop.create_task(func())
t2 = loop.create_task(func())
waite_obj = asyncio.wait([t1, t2])
loop.run_until_complete(waite_obj)
print(t1.result())
print(t2.result())
'''
start...
start...
end....
end....
123
123
'''
# 写法2
# loop = asyncio.get_event_loop()
# task_list = [loop.create_task(func()) for i in range(5)]
# waite_obj = asyncio.wait(task_list)
# loop.run_until_complete(waite_obj)
#
# for i in task_list:
# print(i.result())
'''
start...
start...
start...
start...
start...
end....
end....
end....
end....
end....
123
123
123
123
123
'''
上面的执行顺序虽然是并发,但也是按照任务启动的顺序来执行的。
下面的示例是协程实现并发,且谁先执行完谁返回:
import asyncio
from bs4 import BeautifulSoup
async def func(i):
reader, writer = await asyncio.open_connection('www.baidu.com', 80)
writer.write(b'GET / HTTP/1.1\r\nHOST:www.baidu.com\r\nConnection:close\r\n\r\n')
html = ''
async for line in reader:
html += line.decode() + '\n'
soup = BeautifulSoup(html, 'html.parser')
title = soup.find(name='title').text
return title, 'task num: {}'.format(i)
async def main():
task_list = []
for i in range(1, 11):
task = asyncio.ensure_future(func(i))
task_list.append(task)
for result in asyncio.as_completed(task_list):
result = await result
print(result)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
"""
('百度一下,你就知道', 'task num: 1')
('百度一下,你就知道', 'task num: 3')
('百度一下,你就知道', 'task num: 4')
('百度一下,你就知道', 'task num: 2')
('百度一下,你就知道', 'task num: 6')
('百度一下,你就知道', 'task num: 5')
('百度一下,你就知道', 'task num: 10')
('百度一下,你就知道', 'task num: 8')
('百度一下,你就知道', 'task num: 7')
('百度一下,你就知道', 'task num: 9')
"""
虽然实现了,谁先完事儿谁返回的效果,但很明显,你要直接用asyncio
来搞爬虫,那肯定要劝退了,因为自己实现太麻烦了,也太难了!所以,这里只是演示使用asyncio
来实现爬虫,但真正的写并发爬虫都是用别的模块,比如使用aiohttp
模块,它封装了asyncio
,也封装了http相关模块。
that's all