Python协程技术:从Greenlet到async/await的异步编程探索

协程:

​ 协程,在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协程技术:从Greenlet到async/await的异步编程探索_第1张图片

协程的实现

在Python中,有多种方式可以实现协程。以下是其中几种常用的方式:

  • 使用第三方模块greenlet:greenlet是一个第三方库,它提供了协程的支持。通过使用greenlet,可以手动控制协程的切换,并实现协程之间的交替执行。
  • 使用生成器(yield):Python中的生成器也可以用于实现协程,通过yield关键字可以暂停函数的执行,并在需要时恢复执行。生成器可以作为协程函数,通过yield来实现协程的切换。
  • 使用asyncio库:Python标准库中的asyncio模块提供了对协程的支持。asyncio提供了事件循环(event loop)和协程(coroutine)的概念,可以通过async/await关键字来定义和管理协程,实现异步编程。
  • 使用async/await关键字:在Python 3.5及更高版本中,引入了async/await关键字,使得编写和管理协程更加方便。通过使用async/await关键字结合asyncio库,可以轻松地定义和管理协程,并实现异步编程。
1.greenlet
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 函数

Python协程技术:从Greenlet到async/await的异步编程探索_第2张图片

提示:switch中也可以传递参数用于在切换执行时相互传递值。

2. yield

​ 生成器的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协程技术:从Greenlet到async/await的异步编程探索_第3张图片

3.asyncio

在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协程技术:从Greenlet到async/await的异步编程探索_第4张图片

4 async & awit

在Python 3.5版本中,引入了asyncawait关键字,它们被用作协程的定义和异步操作的等待。相比于使用@asyncio.coroutine装饰器和yield from语法,使用asyncawait关键字能够使协程代码更加简洁和易读。

从Python 3.8版本开始,官方已经不推荐使用@asyncio.coroutine装饰器,而是建议直接使用asyncawait关键字来定义协程函数和等待异步操作的完成。这样可以提高代码的可读性和维护性,同时也更符合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),它负责调度和执行协程任务。通过使用asyncawait关键字,可以定义协程函数,并在协程函数内使用await关键字来暂停协程的执行,等待异步操作的完成。

总结:

​ 在本文中,我们深入探索了Python中的协程技术,从传统的Greenlet和yield到新的async/await关键字,涵盖了多种实现协程的方法。通过这些技术,我们能够以非阻塞的方式处理并发和异步操作,提高程序的性能和响应能力。

​ 协程是一种轻量级的并发编程模型,允许我们在单个线程内实现多个独立的执行流。使用Greenlet和yield,我们可以手动切换协程的执行,实现协程间的协作。这种方式虽然灵活,但需要手动编写切换逻辑,不太直观。

​ 随着asyncio模块的引入,Python提供了更高级的异步编程功能。通过使用其中的协程和事件循环,我们可以更方便地定义和调度协程,处理IO密集型任务和并发操作。asyncio提供了丰富的工具和函数,使得异步编程变得简洁和可读性更强。

​ 最新的async/await关键字进一步简化了协程的编写和理解。通过使用async/await,我们可以直接在协程函数中等待异步操作的完成,而不再需要使用yield from语法。这使得协程代码更加易读和直观,符合Python的语法风格。

​ 总而言之,协程技术为我们提供了一种高效的并发编程方式。无论是处理IO密集型任务还是构建高性能的网络应用,协程都能发挥重要的作用。通过选择合适的工具和语法,我们可以根据具体的需求和编程风格,灵活地应用协程技术。掌握协程的概念和实现方式,将有助于提升代码的性能和可维护性,让我们在异步编程的世界中更加游刃有余。

你可能感兴趣的:(Python基础,python,开发语言)