美文网首页
14. 单线程+异步协程

14. 单线程+异步协程

作者: 薛东弗斯 | 来源:发表于2024-03-02 06:45 被阅读0次
高性能异步爬虫
目的:在爬虫中使用异步实现高性能的数据爬取操作。

异步爬虫的方式:
    - 1.多线程,多进程(不建议):
        好处:可以为相关阻塞的操作单独开启线程或者进程,阻塞操作就可以异步执行。
        弊端:无法无限制的开启多线程或者多进程。
    - 2.线程池、进程池(适当的使用):
        好处:我们可以降低系统对进程或者线程创建和销毁的一个频率,从而很好的降低系统的开销。
        弊端:池中线程或进程的数量是有上限。

- 3.单线程+异步协程(推荐):
    event_loop:事件循环,相当于一个无限循环,我们可以把一些函数注册到这个事件循环上,
    当满足某些条件的时候,函数就会被循环执行。

    coroutine:协程对象,我们可以将协程对象注册到事件循环中,它会被事件循环调用。
    我们可以使用 async 关键字来定义一个方法,这个方法在调用时不会立即被执行,而是返回
    一个协程对象。

    task:任务,它是对协程对象的进一步封装,包含了任务的各个状态。

    future:代表将来执行或还没有执行的任务,实际上和 task 没有本质区别。

    async 定义一个协程.

    await 用来挂起阻塞方法的执行。
import asyncio

async def request(url):
    print('正在请求的url是',url)
    print('请求成功,',url)
    return url
#async修饰的函数,调用之后返回的一个协程对象
c = request('www.baidu.com')

# #创建一个事件循环对象
# loop = asyncio.get_event_loop()
#
# #将协程对象注册到loop中,然后启动loop
# loop.run_until_complete(c)

#task的使用
# loop = asyncio.get_event_loop()
# #基于loop创建了一个task对象
# task = loop.create_task(c)
# print(task)
#
# loop.run_until_complete(task)
#
# print(task)

#future的使用
# loop = asyncio.get_event_loop()
# task = asyncio.ensure_future(c)
# print(task)
# loop.run_until_complete(task)
# print(task)

def callback_func(task):
    #result返回的就是任务对象中封装的协程对象对应函数的返回值
    print(task.result())

#绑定回调
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(c)
#将回调函数绑定到任务对象中
task.add_done_callback(callback_func)
loop.run_until_complete(task)

import asyncio
import time

async def request(url):
    print('downloading...',url)
    # 在异步协同中如果出现了同步模块相关的代码,那么就无法实现异步
    # time.sleep(2)  # 同步操作,此时执行为串行,同步执行,执行时间6秒
    # asyncio中遇到阻塞,必须手动挂起
    await asyncio.sleep(2)  # 异步操作,此时执行时间2秒
    print('download succeed!',url)

urls = [
    'www.baidu.com',
    'www.sohu.com',
    'www.sougou.com'
]
start = time.time()
# 任务列表,需要存放多个任务
atasks = []
for url in urls:
    c = request(url)
    task = asyncio.ensure_future(c)
    atasks.append(task)

loop = asyncio.get_event_loop()
# 需要将任务列表封装到wait中
loop.run_until_complete(asyncio.wait(atasks))
print(time.time() - start)

requests.get基于同步,下面代码不会被执行

import requests
import asyncio
import time

urls = [
    'www.baidu.com',
    'www.sohu.com',
    'www.sougou.com'
]
tasks = []
start = time.time()
async  def get_page(url):
    print('downloading...', url)
    # requests.get是基于同步,必须使用基于异步的网络请求模块进行指定url的请求发送
    # aiohttp:基于异步网络请求的模块
    response = requests.get(url = urls)  # 该代码是同步模块,无法发起异步。 request的请求是基于同步的。
    print('download complete', response.text)

for url in urls:
    c = get_page(url)
    task = asyncio.ensure_future(c)
    tasks.append(task)

loop = asyncio.get_event_loop()
# 需要将任务列表封装到wait中
loop.run_until_complete(asyncio.wait(tasks))
end = time.time()
print("time consumed: ",end-start)

基于aiohttp模块实现异步

#安装模块 pip insall aiohttp
import aiohttp
import requests
import asyncio
import time

urls = [
    'www.baidu.com',
    'www.sohu.com',
    'www.sougou.com'
]
tasks = []
start = time.time()
async  def get_page(url):
    print('downloading...', url)
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            page_text = await response.text()
            # text()返回字符串形式的响应数据
            # read()返回二进制形式的响应数据
            # json()返回的就是json对象
            # 获取响应数据操作之前,一定要用使await进行手动挂起
            print(page_text)

for url in urls:
    c = get_page(url)
    task = asyncio.ensure_future(c)
    tasks.append(task)

loop = asyncio.get_event_loop()
# 需要将任务列表封装到wait中
loop.run_until_complete(asyncio.wait(tasks))
end = time.time()
print("time consumed: ",end-start)

相关文章

网友评论

      本文标题:14. 单线程+异步协程

      本文链接:https://www.haomeiwen.com/subject/svaczdtx.html