协程,在Python中,协程是一种轻量级的并发编程方式,它允许在单个线程内实现多个独立的执行流。协程可以在不同的执行点之间进行切换,而无需依赖于操作系统的线程切换。这使得协程成为处理高并发和异步任务的有力工具。
def func1():
print(1)
...
print(2)
def func2():
print(3)
...
print(4)
func1()
func2()
上述代码是普通的函数定义和执行,按流程分别执行两个函数中的代码,并先后会输出:1、2、3、4
。但如果介入协程技术那么就可以实现函数见代码切换执行,最终输入:1、3、2、4
。
例如:下面的代码可以实现协程
import asyncio
async def func1():
print(1)
await asyncio.sleep(1) # 模拟耗时操作
print(2)
async def func2():
print(3)
await asyncio.sleep(1) # 模拟耗时操作
print(4)
async def main():
await asyncio.gather(func1(), func2())
asyncio.run(main())
在Python中,有多种方式可以实现协程。以下是其中几种常用的方式:
from greenlet import greenlet
def func1():
print(1) # 第1步:输出 1
gr2.switch() # 第3步:切换到 func2 函数
print(2) # 第6步:输出 2
gr2.switch() # 第7步:切换到 func2 函数,从上一次执行的位置继续向后执行
def func2():
print(3) # 第4步:输出 3
gr1.switch() # 第5步:切换到 func1 函数,从上一次执行的位置继续向后执行
print(4) # 第8步:输出 4
gr1 = greenlet(func1)
gr2 = greenlet(func2)
gr1.switch() # 第1步:去执行 func1 函数
提示:switch中也可以传递参数用于在切换执行时相互传递值。
生成器的yield
关键字可以用于实现协程代码。通过使用yield
,可以将函数切分为多个可暂停和恢复的执行点,从而实现协程的切换。
yield from
可以用于等待另一个协程的执行,并将控制权转移到该协程,直到它完成或产生结果。这样可以实现协程的嵌套和协作,使得协程能够在遇到IO操作时暂停执行,并自动切换到其他协程
def func1():
yield 1
yield from func2()
yield 2
def func2():
yield 3
yield 4
f1 = func1()
for item in f1:
print(item)
在Python 3.4发布后,官方引入了asyncio
模块,为Python提供了官方支持的协程和异步编程框架。asyncio
模块基于事件循环和协程的概念,提供了一种方便的编程模型来实现异步操作。
import asyncio
@asyncio.coroutine
def func1():
print(1)
yield from asyncio.sleep(2) # 遇到IO耗时操作,自动化切换到tasks中的其他任务
print(2)
@asyncio.coroutine
def func2():
print(3)
yield from asyncio.sleep(2) # 遇到IO耗时操作,自动化切换到tasks中的其他任务
print(4)
tasks = [
asyncio.ensure_future( func1() ),
asyncio.ensure_future( func2() )
]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
在Python 3.5版本中,引入了async
和await
关键字,它们被用作协程的定义和异步操作的等待。相比于使用@asyncio.coroutine
装饰器和yield from
语法,使用async
和await
关键字能够使协程代码更加简洁和易读。
从Python 3.8版本开始,官方已经不推荐使用@asyncio.coroutine
装饰器,而是建议直接使用async
和await
关键字来定义协程函数和等待异步操作的完成。这样可以提高代码的可读性和维护性,同时也更符合Python语言的发展趋势。
import asyncio
async def func1():
print(1)
await asyncio.sleep(2) # 遇到IO耗时操作,自动化切换到tasks中的其他任务
print(2)
async def func2():
print(3)
await asyncio.sleep(2) # 遇到IO耗时操作,自动化切换到tasks中的其他任务
print(4)
tasks = [
asyncio.ensure_future(func1()), # 将func1协程函数转换为Task对象
asyncio.ensure_future(func2()) # 将func2协程函数转换为Task对象
]
loop = asyncio.get_event_loop() # 创建事件循环对象
loop.run_until_complete(asyncio.wait(tasks)) # 运行协程任务直到所有任务完成
asyncio
模块的核心是事件循环(event loop),它负责调度和执行协程任务。通过使用async
和await
关键字,可以定义协程函数,并在协程函数内使用await
关键字来暂停协程的执行,等待异步操作的完成。
在本文中,我们深入探索了Python中的协程技术,从传统的Greenlet和yield到新的async/await关键字,涵盖了多种实现协程的方法。通过这些技术,我们能够以非阻塞的方式处理并发和异步操作,提高程序的性能和响应能力。
协程是一种轻量级的并发编程模型,允许我们在单个线程内实现多个独立的执行流。使用Greenlet和yield,我们可以手动切换协程的执行,实现协程间的协作。这种方式虽然灵活,但需要手动编写切换逻辑,不太直观。
随着asyncio模块的引入,Python提供了更高级的异步编程功能。通过使用其中的协程和事件循环,我们可以更方便地定义和调度协程,处理IO密集型任务和并发操作。asyncio提供了丰富的工具和函数,使得异步编程变得简洁和可读性更强。
最新的async/await关键字进一步简化了协程的编写和理解。通过使用async/await,我们可以直接在协程函数中等待异步操作的完成,而不再需要使用yield from语法。这使得协程代码更加易读和直观,符合Python的语法风格。
总而言之,协程技术为我们提供了一种高效的并发编程方式。无论是处理IO密集型任务还是构建高性能的网络应用,协程都能发挥重要的作用。通过选择合适的工具和语法,我们可以根据具体的需求和编程风格,灵活地应用协程技术。掌握协程的概念和实现方式,将有助于提升代码的性能和可维护性,让我们在异步编程的世界中更加游刃有余。