解锁Python异步编程的秘密

在现代编程中,异步编程已成为处理I/O密集型任务的重要工,它不仅可以提高程序的响应速度,还能有效利用系统资源。上篇文章中简单介绍了并行、并发的概念,也顺带介绍了异步编程的一些基础知识;今天,本文将带你深入了解Python中的异步编程,学习如何使用`asyncio`库进行异步任务管理,并通过多个实战示例展示其强大之处。 [TOC] ### 什么是异步编程? 异步编程是一种并发编程的方法,它允许程序在等待某个耗时操作(如网络请求、文件读写)完成时,不必阻塞当前线程,而是继续执行其他任务。这种方式可以显著提高程序的效率,特别是在处理I/O密集型任务时。 #### 同步与异步的对比 在传统的同步编程中,代码按顺序执行,一个任务完成后才能开始下一个任务;如果某个任务需要等待(如网络请求),整个程序就会被阻塞。在异步编程中,任务可以在等待期间让出控制权,其他任务可以继续执行。这种非阻塞的执行方式提高了程序的并发性和资源利用率。 #### 使用场景 异步编程特别适用于以下场景: - **网络请求**:如HTTP请求、WebSocket通信等。 - **文件I/O**:处理大规模文件的读写操作。 - **数据库操作**:如数据库查询、写入等。 ### Python中的异步编程 在Python中,异步编程主要通过`asyncio`库实现。`asyncio`是Python标准库的一部分,专门用于编写并发代码。 #### 基本概念 - **`async` 和 `await` 关键字**:`async`用于定义异步函数,`await`用于等待耗时操作的完成; - **事件循环**:`asyncio`的核心组件,负责调度并运行异步任务; - **协程**:使用`async`定义的函数,其执行可以被挂起和恢复; #### 创建异步函数 首先,我们需要定义一个异步函数: ```python import asyncio async def say_hello(): print("Hello, World!") await asyncio.sleep(1) print("Hello again!") ``` #### 运行异步函数 要运行异步函数,我们需要使用事件循环: ```python async def main(): await say_hello() asyncio.run(main()) ``` #### 创建并运行多个任务 我们可以同时运行多个异步任务: ```python 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`库,可以方便地进行异步文件读写: ```python 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请求: ```python 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`进行实际开发: ```python 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`实现这一点: ```python 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()) ``` #### 加入错误处理 在异步编程中,处理错误同样重要。可以使用`try`和`except`语句来捕获和处理异步任务中的异常: ```python 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`可以确保资源的正确打开和关闭,例如数据库连接、文件句柄等: ```python 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__`方法可以定义一个异步迭代器: ```python 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 def`和`yield`关键字可以定义一个异步生成器: ```python 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](https://mdnice.com/?platform=6)多平台发布
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351

推荐阅读更多精彩内容