网站开发培训学校,wordpress联动筛选模板,如何进行网站icp备案,wordpress文章类型模板是一种处理多个任务同时执行的编程方式#xff0c;在Python中#xff0c;asyncio是一种用于实现异步编程的强大工具。asyncio基于协程#xff08;coroutine#xff09;的概念#xff0c;能够高效地处理I/O密集型任务。本文将介绍asyncio的基本原理和使用方法。
为啥需要a…是一种处理多个任务同时执行的编程方式在Python中asyncio是一种用于实现异步编程的强大工具。asyncio基于协程coroutine的概念能够高效地处理I/O密集型任务。本文将介绍asyncio的基本原理和使用方法。
为啥需要asyncio
我们知道在处理 I/O 操作时使用多线程与普通的单线程相比效率得到了极大的提高。既然这样为什么还需要 Asyncio
多线程有诸多优点且应用广泛但也存在一定的局限性
比如多线程运行过程容易被打断因此有可能出现 race condition 的情况 再如线程切换本身存在一定的损耗线程数不能无限增加因此如果你的 I/O 操作非常 heavy多线程很有可能满足不了高效率、高质量的需求。 正是为了解决这些问题Asyncio 应运而生。
Sync VS Async
我们首先来区分一下 Sync同步和 Async异步的概念。
所谓 Sync是指操作一个接一个地执行下一个操作必须等上一个操作完成后才能执行。而 Async 是指不同操作间可以相互交替执行如果其中的某个操作被 block 了程序并不会等待而是会找出可执行的操作继续执行。
Asyncio 工作原理
协程CoroutinesAsyncio 使用协程来实现异步操作。协程是一种特殊的函数使用 async 关键字定义。在协程中可以使用 await 关键字暂停当前协程的执行等待一个异步操作完成。
事件循环Event Loop事件循环是 Asyncio 的核心机制之一。它负责调度和执行协程并处理协程之间的切换。事件循环会不断地轮询可执行的任务一旦某个任务就绪如 IO 完成或定时器到期事件循环会将其放入执行队列并继续执行下一个任务。
异步任务Async Tasks在 Asyncio 中我们通过创建异步任务来执行协程。异步任务由 asyncio.create_task() 函数创建它将协程封装成一个可等待对象并提交给事件循环进行处理。 异步 IO 操作Asyncio 提供了一组异步的 IO 操作如网络请求、文件读写等这些操作可以通过协程和事件循环无缝地进行集成。通过使用异步 IO 操作可以避免在等待 IO 完成时发生阻塞提高程序的性能和并发性。
回调CallbacksAsyncio 也支持使用回调函数处理异步操作的结果。可以通过使用
asyncio.ensure_future() 函数将回调函数封装为一个可等待对象并提交给事件循环进行处理。
并发执行Asyncio 可以并发执行多个协程任务。事件循环会根据任务的就绪情况自动调度协程的执行从而实现高效的并发编程。
总结起来Asyncio 的工作原理是基于协程和事件循环的机制。通过使用协程进行异步操作并由事件循环负责协程的调度和执行Asyncio 实现了高效的异步编程模型。
协程与异步编程
协程是asyncio中的重要概念它是一种轻量级的执行单位可以在任务之间进行快速切换而无需线程切换的开销。协程可以通过async关键字定义而await关键字用于暂停协程的执行等待某个操作完成后再继续执行。
以下是一个简单的示例代码演示了如何使用协程进行异步编程
import asyncio
async def hello():print(Hello)await asyncio.sleep(1) # 模拟耗时操作print(World)
# 创建一个事件循环
loop asyncio.get_event_loop()
# 将协程加入事件循环并执行
loop.run_until_complete(hello())在这个示例中函数hello()是一个协程通过async关键字进行定义。在协程内部我们可以使用await来暂停协程的执行这里使用asyncio.sleep(1)模拟一个耗时操作。通过run_until_complete()方法将协程加入事件循环并运行。
异步I/O操作
asyncio主要用于处理I/O密集型任务如网络请求、文件读写等操作。它提供了一系列的异步I/O操作API可与await关键字配合使用轻松实现异步编程。
以下是一个简单的示例代码展示了如何使用asyncio进行异步网络请求
import asyncio
import aiohttp
async def fetch(session, url):async with session.get(url) as response:return await response.text()
async def main():async with aiohttp.ClientSession() as session:html await fetch(session, https://www.example.com)print(html)
# 创建一个事件循环
loop asyncio.get_event_loop()
# 将协程加入事件循环并执行
loop.run_until_complete(main())
在这个示例中我们使用了aiohttp库进行网络请求。函数fetch()是一个协程通过session.get()方法发起异步GET请求并通过await关键字等待响应返回。函数main()是另一个协程内部创建了一个ClientSession对象来重复使用然后调用fetch()方法获取网页内容并打印。
注意
看到这里我们使用了aiohttp而没有使用requests库是因为requests 库并不兼容 Asyncio但是 aiohttp 库兼容。
想用好 Asyncio特别是发挥其强大的功能很多情况下必须得有相应的 Python 库支持
并发执行多个任务
asyncio还提供了一些用于并发执行多个任务的机制如asyncio.gather()和asyncio.wait()等。下面是一个示例代码展示了如何使用这些机制并发执行多个协程任务
import asyncio
async def task1():print(Task 1 started)await asyncio.sleep(1)print(Task 1 finished)
async def task2():print(Task 2 started)await asyncio.sleep(2)print(Task 2 finished)
async def main():await asyncio.gather(task1(), task2())
# 创建一个事件循环
loop asyncio.get_event_loop()
# 将协程加入事件循环并执行
loop.run_until_complete(main())
在这个示例中我们定义了两个协程任务task1()和task2()它们都进行了一些耗时操作。协程main()通过asyncio.gather()同时启动这两个任务并等待它们完成。通过并发执行可以提高程序的执行效率。
如何选择
实际项目中到底选择多线程还是asyncio呢有位大佬这样总结的很形象
if io_bound:if io_slow:print(Use Asyncio)else:print(Use multi-threading)
else if cpu_bound:print(Use multi-processing)如果是 I/O bound并且 I/O 操作很慢需要很多任务 / 线程协同实现那么使用 Asyncio 更合适。 如果是 I/O bound但是 I/O 操作很快只需要有限数量的任务 / 线程那么使用多线程就可以了。 如果是 CPU bound则需要使用多进程来提高程序运行效率。
实战
输入一个列表对于列表中的每个元素我想计算 0 到这个元素的所有整数的平方和。
同步实现
import time
def cpu_bound(number):return sum(i * i for i in range(number))
def calculate_sums(numbers):for number in numbers:cpu_bound(number)
def main():start_time time.perf_counter()numbers [10000000 x for x in range(20)]calculate_sums(numbers)end_time time.perf_counter()print(Calculation takes {} seconds.format(end_time - start_time))
if __name__ __main__:main()
执行时间需要Calculation takes 17.976343413000002 seconds
异步实现
concurrent.futures实现
import time
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor, as_completed
def cpu_bound(number):return sum(i * i for i in range(number))
def calculate_sums(numbers):with ProcessPoolExecutor() as executor:results executor.map(cpu_bound, numbers)results [result for result in results]print(results)
def main():start_time time.perf_counter()numbers [10000000 x for x in range(20)]calculate_sums(numbers)end_time time.perf_counter()print(Calculation takes {} seconds.format(end_time - start_time))
if __name__ __main__:main()
执行时间需要Calculation takes 7.314132894999999 seconds.
在这个改进的代码中我们使用 concurrent.futures.ProcessPoolExecutor 来创建一个进程池然后通过 executor.map() 方法来提交任务和获取结果。
请注意在使用 executor.map() 后如果需要获取结果可以将结果迭代为一个列表或者使用其他方法对结果进行处理。
multiprocessing实现
import time
import multiprocessing
def cpu_bound(number):return sum(i * i for i in range(number))
def calculate_sums(numbers):with multiprocessing.Pool() as pool:pool.map(cpu_bound, numbers)
def main():start_time time.perf_counter()numbers [10000000 x for x in range(20)]calculate_sums(numbers)end_time time.perf_counter()print(Calculation takes {} seconds.format(end_time - start_time))
if __name__ __main__:main()
执行用时Calculation takes 6.051121667 seconds
concurrent.futures.ProcessPoolExecutor 和 multiprocessing 都是 Python 中用于实现多进程并发的库它们有一些区别。
基于接口的封装concurrent.futures.ProcessPoolExecutor 是 concurrent.futures 模块提供的一个高级接口它对底层的多进程功能进行了封装使得编写多进程代码更加简单。而 multiprocessing 则是 Python 的标准库之一提供了完整的多进程支持并允许直接操作进程。API 使用方式concurrent.futures.ProcessPoolExecutor 的使用方式类似于线程池它通过提交可调用对象如函数到进程池中执行并返回一个 Future 对象可以用来获取执行结果。而 multiprocessing 提供了更底层的进程管理和通信接口可以显式地创建、启动和控制进程并使用多个进程之间的队列或管道进行通信。可扩展性和灵活性由于 multiprocessing 提供了更底层的接口因此它相对于 concurrent.futures.ProcessPoolExecutor 来说更加灵活。通过直接操作进程可以对每个进程进行更细粒度的控制如设置进程优先级、进程间共享数据等。而 concurrent.futures.ProcessPoolExecutor 更适合于简单的任务并行化它隐藏了许多底层的细节使得编写多进程代码更加简单和易用。跨平台支持concurrent.futures.ProcessPoolExecutor 和 multiprocessing 都提供了跨平台的多进程支持可以在各种操作系统上使用。
综上所述concurrent.futures.ProcessPoolExecutor 是一个高级接口封装了底层的多进程功能适用于简单的多进程任务并行化。而 multiprocessing 是一个更底层的库提供了更多的控制和灵活性适用于需要精细控制进程的场景。
需要根据具体需求选择合适的库如果只是简单的任务并行化可以使用 concurrent.futures.ProcessPoolExecutor 来简化代码如果需要更底层的控制和通信可以使用 multiprocessing 库。
最后
不同于多线程Asyncio 是单线程的但其内部 event loop 的机制可以让它并发地运行多个不同的任务并且比多线程享有更大的自主控制权。
Asyncio 中的任务在运行过程中不会被打断因此不会出现 race condition 的情况。
尤其是在 I/O 操作 heavy 的场景下Asyncio 比多线程的运行效率更高。因为 Asyncio 内部任务切换的损耗远比线程切换的损耗要小并且 Asyncio 可以开启的任务数量也比多线程中的线程数量多得多。
但需要注意的是很多情况下使用 Asyncio 需要特定第三方库的支持比如前面示例中的 aiohttp。而如果 I/O 操作很快并不 heavy那么运用多线程也能很有效地解决问题。
asyncio是用于实现异步编程的Python库。 协程是asyncio的核心概念通过async和await关键字实现异步操作。 asyncio提供了强大的异步I/O操作API可轻松处理I/O密集型任务。 通过asyncio.gather()等机制可以并发执行多个协程任务。
最后感谢每一个认真阅读我文章的人礼尚往来总是要有的虽然不是什么很值钱的东西如果你用得到的话可以直接拿走 这些资料对于【软件测试】的朋友来说应该是最全面最完整的备战仓库这个仓库也陪伴上万个测试工程师们走过最艰难的路程希望也能帮助到你