Skip to content

12. 协程

计算机中提供了:线程、进程用于实现并发编程。

协程(Coroutine):是程序员通过代码实现出来的(非真实存在),用户态、可暂停/可恢复的函数。 它能在运行中把控制权"主动让出",之后再从让出的地方继续执行。和线程相比,它不靠操作系统抢占调度,而是**主动配合(cooperative)**切换,因此轻量、切换快、能在单线程里跑出"并发感"。

协程也可以被称为微线程,是一种用户态内的上下文切换技术。 简而言之,其实就是通过一个线程实现代码块相互切换执行(来回跳着执行)

例如:

python
def func1():
    print("func1-1")
    print("func1-2")


def func2():
    print("func2-1")
    print("func2-2")


func1()
func2()

上述代码是普通的函数定义和执行,按照流程分别执行两个函数中的代码,并先后会输出:func1-1、func1-2、func2-1、func2-2。

但如果介入协程技术那么就可以实现函数间代码切换执行,最终输出:func1-1、func2-1、func1-2、func2-2。

实现协程

greenlet

python
from greenlet import greenlet


def func1():
    print(1)
    gr2.switch()  # 切换到 func2 函数
    print(2)
    gr2.switch()


def func2():
    print("A")
    gr1.switch()  # 切换回 func1 函数,从上一次执行的位置继续向后执行
    print("B")


gr1 = greenlet(func1)
gr2 = greenlet(func2)
gr1.switch()  # 去执行 func1 函数

# 输出结果:
# 1
# A
# 2
# B

yield

python
def func1():
    yield 1
    yield from func2()
    yield 2


def func2():
    yield "A"
    yield "B"


f1 = func1()
for item in f1:
    print(item)

# 输出结果:
# 1
# A
# B
# 2

虽然上述两种都实现了协程,但这种编写方式没有意义,手动来回切换执行,可能让程序执行速度更慢

协程的实际应用

不要让用户手动去切换,而是遇到 IO 操作时能自动切换。 Python 中可以使用 asyncio 库来实现这种功能,内部基于协程并且遇到 IO 请求自动化切换。

当遇见有 IO 等待时,可优先使用协程。

python
import asyncio


async def func1():
    print(1)
    await asyncio.sleep(1)
    print(2)


async def func2():
    print(3)
    await asyncio.sleep(1)
    print(4)


tasks = [asyncio.ensure_future(func1()), asyncio.ensure_future(func2())]

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
# 输出结果:
# 1
# 3
# 2
# 4

协程、线程、进程的区别

线程,是计算机中可以被 CPU 调度的最小单元。

进程,是计算机资源分配的最小单元(进程为线程提供资源)。

一个进程中可以有多个线程,同一个进程中的线程可以共享此进程中的资源。

进程与进程之间是相互独立的,进程之间的数据不共享。

由于 CPython 中 GIL 的存在:

  • 线程,适用于 IO 密集型操作。
  • 进程,适用于计算密集型操作。

协程,协程也可以被称为微线程,是一种用户态内的上下文切换技术。在开发中结合遇到 IO 自动切换,就可以通过一个线程实现并发操作。

所以,在处理 IO 操作时,协程比线程更加节省开销(协程的开发难度大一些)。

构建时间:11/21/2025, 1:28:39 PM | 本博客内容均为自己学习,如内容涉及侵权,请联系邮箱:pangzl0215@163.com