​ 在现代编程中,异步编程已成为处理I/O密集型任务的重要工,它不仅可以提高程序的响应速度,还能有效利用系统资源。上篇文章中简单介绍了并行、并发的概念,也顺带介绍了异步编程的一些基础知识;今天,本文将带你深入了解Python中的异步编程,学习如何使用asyncio库进行异步任务管理,并通过多个实战示例展示其强大之处。

[TOC]

什么是异步编程?

​ 异步编程是一种并发编程的方法,它允许程序在等待某个耗时操作(如网络请求、文件读写)完成时,不必阻塞当前线程,而是继续执行其他任务。这种方式可以显著提高程序的效率,特别是在处理I/O密集型任务时。

同步与异步的对比

在传统的同步编程中,代码按顺序执行,一个任务完成后才能开始下一个任务;如果某个任务需要等待(如网络请求),整个程序就会被阻塞。在异步编程中,任务可以在等待期间让出控制权,其他任务可以继续执行。这种非阻塞的执行方式提高了程序的并发性和资源利用率。

使用场景

异步编程特别适用于以下场景:

  • 网络请求:如HTTP请求、WebSocket通信等。
  • 文件I/O:处理大规模文件的读写操作。
  • 数据库操作:如数据库查询、写入等。

Python中的异步编程

在Python中,异步编程主要通过asyncio库实现。asyncio是Python标准库的一部分,专门用于编写并发代码。

基本概念

  • asyncawait 关键字async用于定义异步函数,await用于等待耗时操作的完成;
  • 事件循环asyncio的核心组件,负责调度并运行异步任务;
  • 协程:使用async定义的函数,其执行可以被挂起和恢复;

创建异步函数

首先,我们需要定义一个异步函数:

import asyncio

async def say_hello():
    print("Hello, World!")
    await asyncio.sleep(1)
    print("Hello again!")

运行异步函数

要运行异步函数,我们需要使用事件循环:

async def main():
    await say_hello()

asyncio.run(main())

创建并运行多个任务

我们可以同时运行多个异步任务:

async def task1():
    print("Task 1 started")
    await asyncio.sleep(2)
    print("Task 1 completed")

async def task2():
    print("Task 2 started")
    await asyncio.sleep(1)
    print("Task 2 completed")

async def main():
    await asyncio.gather(task1(), task2())

asyncio.run(main())

异步I/O操作

异步编程的一个主要应用场景是I/O操作,包括文件读写、网络请求等,我们可以使用aiofiles库进行异步文件操作,使用aiohttp库进行异步网络请求。

异步文件操作

使用aiofiles库,可以方便地进行异步文件读写:

import aiofiles

async def read_file(filename):
    async with aiofiles.open(filename, 'r') as f:
        contents = await f.read()
        print(contents)

asyncio.run(read_file('example.txt'))

异步网络请求

使用aiohttp库,可以方便地进行异步HTTP请求:

import aiohttp

async def fetch(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()

async def main():
    content = await fetch('http://example.com')
    print(content)

asyncio.run(main())

异步网络爬虫

我们将通过一个异步网络爬虫的示例,展示如何使用asyncio进行实际开发:

import asyncio
import aiohttp

async def fetch(url):
    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 = [fetch(url) for url in urls]
    results = await asyncio.gather(*tasks)
    for result in results:
        print(result[:100])  # 打印前100个字符

asyncio.run(main())

加入并发限制

在实际应用中,我们可能需要限制并发请求的数量,以避免对目标服务器造成过大压力,可以使用asyncio.Semaphore实现这一点:

import asyncio
import aiohttp

semaphore = asyncio.Semaphore(5)

async def fetch(url):
    async with semaphore:
        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',
        # 添加更多URL
    ]
    tasks = [fetch(url) for url in urls]
    results = await asyncio.gather(*tasks)
    for result in results:
        print(result[:100])  # 打印前100个字符

asyncio.run(main())

加入错误处理

在异步编程中,处理错误同样重要。可以使用tryexcept语句来捕获和处理异步任务中的异常:

import asyncio
import aiohttp

async def fetch(url):
    try:
        async with aiohttp.ClientSession() as session:
            async with session.get(url) as response:
                response.raise_for_status()  # 检查HTTP状态码
                return await response.text()
    except aiohttp.ClientError as e:
        print(f"Error fetching {url}: {e}")
        return None

async def main():
    urls = [
        'http://example.com',
        'http://invalid-url',  # 错误的URL
        'http://example.net',
    ]
    tasks = [fetch(url) for url in urls]
    results = await asyncio.gather(*tasks)
    for result in results:
        if result:
            print(result[:100])  # 打印前100个字符

asyncio.run(main())

异步上下文管理器

在Python的异步编程中,异步上下文管理器是一个非常重要的概念,使用async with可以确保资源的正确打开和关闭,例如数据库连接、文件句柄等:

import asyncio
import aiofiles

async def read_file(filename):
    async with aiofiles.open(filename, 'r') as f:
        contents = await f.read()
        print(contents)

asyncio.run(read_file('example.txt'))

异步迭代器

异步迭代器允许我们在迭代时等待异步操作完成,使用__aiter____anext__方法可以定义一个异步迭代器:

class AsyncIterator:
    def __init__(self, n):
        self.n = n
        self.i = 0

    def __aiter__(self):
        return self

    async def __anext__(self):
        if self.i < self.n:
            self.i += 1
            await asyncio.sleep(1)
            return self.i
        else:
            raise StopAsyncIteration

async def main():
    async for i in AsyncIterator(5):
        print(i)

asyncio.run(main())

异步生成器

异步生成器允许我们在生成值时等待异步操作完成,使用async defyield关键字可以定义一个异步生成器:

async def async_gen(n):
    for i in range(n):
        await asyncio.sleep(1)
        yield i

async def main():
    async for i in async_gen(5):
        print(i)

asyncio.run(main())

结语

​ 异步编程是处理I/O密集型任务的利器,它可以大幅提高程序的响应速度和资源利用率。希望通过本文的介绍,大家能对Python中的异步编程有比较全面的了解,并掌握asyncio库的基本使用;如果能将这些知识应用到你的实际项目中,那这篇文章的使命就算很好的完成了!

​ 如果你对计算机相关技术有更多的兴趣,想要持续的探索,请关注我的公众号哟!

本文由mdnice多平台发布


小新
1 声望0 粉丝