python异步编程

python异步编程主要用于IO密集型任务,如网络请求、文件读写等,可以有效提高程序的执行效率。

1.同步编程

import requests


def fetch_url(url):
    response = requests.get(url)
    # 模拟网络io响应时间,程序就会在这里阻塞住。
    # 这段时间也不能去处理其他事情。
    # time.sleep(3)
    return response.text

# 使用示例
url = "http://example.com"
result = fetch_url(url)
print(result)

2.异步编程

为了将上述同步请求转换为异步请求,我们可以使用aiohttp库,这是一个基于asyncio的HTTP客户端/服务器框架。

首先,需要安装aiohttp库(如果尚未安装):

pip install aiohttp

然后,编写异步HTTP请求的代码:

import aiohttp
import asyncio


async def fetch_url(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()
            # 使用asyncio运行异步函数

async def main():
    url = "http://example.com"
    result = await fetch_url(url)
    print(result)
    # 不是并发的异步编程,看不出什么效果


# Python 3.7+
asyncio.run(main())

在这个异步示例中,fetch_url函数被声明为async,这意呀着它内部可以包含await表达式。我们使用aiohttp.ClientSession()来创建一个会话,然后通过会话发起异步GET请求。请求的结果是一个aiohttp.ClientResponse对象,我们通过调用其text()方法并等待(await)其结果来获取响应文本。

最后,我们使用asyncio.run(main())来运行我们的异步主程序。

通过这种方式,我们可以将同步的HTTP请求转换为异步的,从而利用asyncio的优势来编写更高效、更易于维护的并发代码。

3.同步

HTTP请求在for循环中的性能问题:等待时间成倍增加

import time

import requests

urls = ["http://example.com", "http://example.org", "http://example.net"]

for url in urls:
    response = requests.get(url)
    time.sleep(3)
    # 同步:3个请求耗时 3*3 秒
    print("时间在白白流逝~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
    print(response.text)  # 这里会等待每个请求完成后再继续

问题表现

  • 等待时间累积:随着循环的进行,整个脚本的执行时间显著增加。这是因为每个HTTP请求都需要一定的时间来完成(包括网络延迟、服务器处理时间等),而这些时间是累加的。
  • 并发限制:如果所有的请求都是顺序发送的(即上一个请求完成后再发送下一个),那么总等待时间将是所有请求时间的总和。
  • 资源瓶颈:如果目标服务器或网络带宽有限,连续的高频请求可能会进一步加剧等待时间,因为服务器可能无法及时处理所有请求。

原因分析

  • 串行执行for循环中的HTTP请求通常是串行执行的,即一个接一个地发送,没有并行处理。
  • 网络延迟和服务器响应:每个请求都需要通过网络发送到服务器,并等待服务器响应。这个过程中包括网络延迟和服务器处理时间,这些时间都是不可忽略的。
  • 线程/进程阻塞:在某些情况下,如果HTTP客户端库或网络栈的实现不是非阻塞的,那么等待响应的过程可能会阻塞当前线程或进程,从而进一步降低程序的并发性能。

解决方案

  1. 使用异步请求:
    • 利用异步编程模型(如Python的asyncio、JavaScript的Promises/Async/Await)来同时发送多个HTTP请求,而不需要等待前一个请求完成。
  2. 限制并发数:
    • 虽然异步请求可以提高效率,但过多的并发请求可能会给服务器或网络带来压力。使用并发限制器(如aiohttpClientSessionconnector.limit参数)来控制同时发送的请求数量。
  3. 优化网络请求:
    • 合并请求:如果可能,将多个请求合并为一个请求,以减少网络往返次数。
    • 缓存结果:对于重复请求的数据,使用缓存来避免不必要的网络请求。
  4. 使用线程或进程池:
    • 在不支持异步编程的环境中,可以使用线程池或进程池来并发执行HTTP请求。

结论

for循环中连续发送HTTP请求时,如果不加以处理,可能会导致等待时间成倍增加。通过采用异步请求、限制并发数、优化网络请求以及使用线程或进程池等策略,可以有效缓解这一问题,提高程序的执行效率和响应速度。

4.异步并发

import time

import aiohttp
import asyncio
async def fetch_url(url):
    print(f"Starting request to {url}")
    # 异步:3个请求耗时 3*1 秒
    await asyncio.sleep(3)  # 模拟网络请求的延时
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()

async def main():
    urls = ["http://example.com", "http://example.org", "http://example.net"]
    tasks = []  # 创建一个空列表来存储协程对象

    # 使用for循环遍历urls,并为每个URL调用fetch_url函数
    # 将返回的协程对象添加到tasks列表中
    for url in urls:
        task = fetch_url(url)
        tasks.append(task)

        # 现在所有任务都已经被添加到tasks列表中,我们可以并发地执行它们
    results = await asyncio.gather(*tasks)

    # 遍历结果并打印
    for result, url in zip(results, urls):
        print(f"Result for {url}: {result[:50]}...")  # 假设我们只打印前50个字符以避免过长输出


# Python 3.7+
asyncio.run(main())

异步编程

异步编程是一种允许程序在等待操作(如I/O操作)完成时继续执行其他任务的编程模型。它通过使用回调函数、Promises、Futures、Async/Await等机制来实现非阻塞的I/O操作。

并发与并行

  • 并发:指多个任务可以同时开始执行,但并不意味着它们会同时运行。并发关注的是任务调度的能力,使得多个任务可以在单个或多个处理器上交错执行。
  • 并行:指多个任务可以同时运行,即在多个处理器上同时执行。并行是并发的一种形式,但并发不一定要求并行。

异步并发解决HTTP请求问题

异步HTTP请求库

许多现代编程语言都提供了支持异步HTTP请求的库,如Python的aiohttp、JavaScript的axios结合async/await、Node.js的fetch API等。

实现步骤

  1. 创建异步函数:使用异步函数(如Python中的async def)来封装HTTP请求逻辑。
  2. 并发执行:使用异步编程的并发控制机制(如Python的asyncio.gather)来同时启动多个异步HTTP请求。
  3. 等待响应:异步等待所有请求完成,并收集响应结果。由于这些请求是并发执行的,因此它们之间的等待时间不会累加。

优点

  • 减少等待时间:由于请求是并发执行的,因此总的等待时间大大缩短。
  • 提高资源利用率:在等待I/O操作(如网络请求)完成时,程序可以执行其他任务,从而提高CPU和网络资源的利用率。
  • 更好的用户体验:在Web应用中,更快的响应时间意味着更好的用户体验。

结论

异步并发是解决for循环中连续发送HTTP请求导致等待时间成倍增加问题的有效方法。通过采用异步编程模型,我们可以同时处理多个HTTP请求,显著提高程序的执行效率和响应速度。在编写涉及大量网络请求的应用程序时,推荐优先考虑使用异步并发技术。

  • 17
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python 异步编程是一种编程范式,它利用并发来提高程序的执行效率,特别是在处理I/O密集型任务时,比如网络请求、文件操作等。异步编程的核心在于避免了线程或进程切换带来的开销,让程序能够更高效地处理多个任务。 在Python中,异步编程主要通过以下几个库来实现: 1. **asyncio**:这是Python标准库的一部分,提供了创建异步任务和协程的基础。通过`async`和`await`关键字,可以编写协程(coroutine),这些是可以在事件循环中运行的轻量级代码块。 2. **Future 和 Task**:`asyncio.Future`和`asyncio.Task`用于封装异步操作的结果,Task是Future的包装器,提供了一些额外的功能,如跟踪状态和取消操作。 3. **Coroutines**(协程):通过定义带有`async def`的函数,函数内部可以使用`await`来挂起执行,直到依赖的异步操作完成。 4. **AIO库**(如Aiohttp、aioredis等):这些第三方库针对特定场景提供了异步版本,如Aiohttp用于非阻塞的HTTP客户端,aioredis用于异步操作Redis数据库。 5. **异步装饰器**:如`@aio.coroutine`(在Python 3.5及更早版本中使用)或`async def`(在Python 3.6及以上版本中)等,可以将常规函数转换为异步协程。 异步编程的一些关键概念包括: - **事件循环**:协调和调度所有协程的运行。 - **异步I/O**:通过非阻塞I/O,允许程序在等待I/O操作完成时继续执行其他任务。 - **回调和生成器**:早期的异步编程可能使用这些技术,但现代Python更倾向于使用async/await和Task。 如果你对异步编程有深入的兴趣,可能会问到: 1. 异步编程如何提高程序性能? 2. Python中如何正确地管理异步任务的执行顺序? 3. 异步编程中的“回调地狱”是什么,如何避免?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值