python3 asyncio库学习(三)—— 协程的超时处理和取消

本文演示了在Python 3.5.2环境下使用asyncio库中的create_subprocess_exec和timeout特性进行异步任务执行及超时处理的方法。注意,不同版本的Python在asyncio接口上存在差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

import asyncio
import os
import time
from asyncio.subprocess import PIPE, STDOUT
from threading import Thread


@asyncio.coroutine
def do_task(domain, loop):
		p = yield from asyncio.create_subprocess_exec('ping', '-c 4  -w 10', domain, stdout=PIPE,loop=loop)
		#task = asyncio.ensure_future(p.stdout.read(),loop=loop)
		#task = asyncio.ensure_future(p.communicate())
		task = asyncio.Task(p.stdout.read(), loop=loop)
		done, pending = yield from asyncio.wait([task], timeout=2, loop=loop)
		if pending:
			print('timeout...........')
			# timeout
			if p.returncode is None:
				# kill the subprocess, then `await future` will return soon
				try:
					p.kill()
				except ProcessLookupError:
					pass

		output = yield from task 
		print(output.decode('utf-8'))
		print('-----------OK----------')


def do_loop(loop):
	asyncio.set_event_loop(loop)
	print('loop starting...................')
	loop.run_forever()


loop= asyncio.new_event_loop()
Thread(target=do_loop, args=(loop,)).start()
domain = 'www.sina.com.cn' 
asyncio.run_coroutine_threadsafe(do_task(domain, loop), loop)
#loop.call_soon_threadsafe(asyncio.async, do_task(domain, loop))
print('after run_coroutine_threadsafe')
#loop.run_forever()​ 

上述代码演示了 asyncio 中create_subprocess_exec, timeout的用法。运行环境 python 3.5.2。
注: python3不同版本间的asyncio库的接口差异有点大,要注意。在python3.6的版本中,上述代码是无法正常运行的。

### Python 中 `asyncio` 及 `await` 关键字使用教程 #### 一、基础概念介绍 在 Python 的异步编程模型中,`asyncio` 是核心之一。它提供了编写单线程并发代码所需的工具,基于协程、事件循环、任务其他原语。 - **协程 (Coroutine)**:由带有 `async def` 声明的函数定义而成的对象。当调用这样的函数时,并不会立即执行其中的内容而是返回一个可以被挂起恢复运行状态的特殊对象——即协程对象[^3]。 - **事件循环 (Event Loop)**:程序启动后进入的一个无限循环过程,在此期间不断监听并处理各种 I/O 或定时器触发的任务。所有的异步操作都依赖于这个中心化的调度机制来协调各个独立工作的单元之间的协作关系[^1]。 - **Task**:为了更好地管理跟踪多个正在运行中的协程实例的状态变化情况而引入的概念;可以通过 `asyncio.create_task()` 方法显式地将某个普通的协程封装成具有更高优先级级别的 Task 实体以便更高效地参与竞争资源分配权衡考量之中。 - **Future**:表示尚未完成的工作的结果。它可以用来桥接同步世界与异步世界的鸿沟,允许我们以一种统一的方式处理来自不同源头的数据流或计算结果。不过这部分内容暂时还未完全展开说明。 #### 二、`await` 关键字详解 `await` 主要用于等待另一个可等待对象(如上述提到过的种类型)结束其工作流程后再继续向下执行后续逻辑分支。需要注意的是只有处于异步上下文中才能合法地运用该语法结构: ```python import asyncio async def fetch_data(url): # 模拟网络请求,这里使用 asyncio.sleep 替代实际 IO 操作 await asyncio.sleep(1) # 此处会暂停当前协程直到睡眠时间到达为止 return f"Data from {url}" ``` 这段代码展示了最简单的形式下如何利用 `await` 来实现非阻塞式的延时效果模拟真实场景下的数据获取行为[^2]。 对于包含多条连续性的 `await` 表达式的场合,则遵循先进先出原则逐个解决每一个待办事项之后才会推进至下一步动作: ```python async def main(): data1 = await fetch_data("https://api.example.com/data1") # 首次遇到 await ,整个方法会被挂起直至左侧表达式求值完毕 print(data1) data2 = await fetch_data("https://api.example.com/data2") # 类似地再次遭遇第二个 await 节点... print(data2) if __name__ == "__main__": asyncio.run(main()) ``` 然而这种串行化的设计模式显然不是最优解方案,特别是在面对大量相似性质的小型子任务集合时效率低下难以满足高性能需求的应用环境要求。因此官方推荐采用批量提交策略并通过诸如 `asyncio.gather()` 函数一次性收集所有预期产出项从而达到提高吞吐量的目的: ```python async def parallel_fetches(): urls = ["https://api.example.com/data{}".format(i) for i in range(1, 4)] tasks = [fetch_data(url) for url in urls] results = await asyncio.gather(*tasks) # 并发执行多个异步操作并将最终得到的所有响应打包在一起返回给调用者 for result in results: print(result) if __name__ == "__main__": asyncio.run(parallel_fetches()) ``` 此外还有其他一些高级特性比如超时控制(`wait_for`)、条件判断(`as_completed`)等可以帮助开发者更加灵活自如地掌控复杂的业务逻辑流转路径。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值