协程和线程

什么是线程和协程?

线程(Thread)和协程(Coroutine)都是为了实现多任务并发处理的编程概念,但它们的实现方式和功能有所不同。

线程:线程是操作系统能够进行运算调度的最小单位。
它被包含在进程中,是进程中的实际运行单位。每个线程都拥有独立的运行栈和程序计数器,并共享同一进程中的各种系统资源如虚拟地址空间初始化代码等。线程之间的切换由操作系统来控制,因此称为内核级别的线程。

协程:协程可以理解为轻量级的线程,也称微线程、纤程。
协程的调度完全由用户程序自控行,称为用户级别的线程。一个程序中的协程,可以象征性的看成一个个独立的小线程,它们之间可以彼此协作,共同完成任务。进入和退出协程的操作相对于线程来说资源开销小的多。

协程和线程的主要区别

管理者:线程是由操作系统管理和调度的,而协程则是由程序代码自身进行管理和调度。也就是说,如果你创建了一个线程,那么何时切换到这个线程、何时切换出这个线程这些决定都是由操作系统来做的。而如果你创建一个协程,那么你需要在代码里显示地指定何时切换任务。

开销:创建和切换线程存在一定的系统调用和上下文切换开销,需要耗费较大的资源,比如保存和恢复线程的执行现场(即线程的一些运行状态),效率较低。而创建和切换协程直接操作内存,没有系统调用的开销,开销则小得多,因此效率较高。所以相比之下,协程能更高效地用于大量的并发任务。

阻塞:当一个线程在等待某些资源,例如磁盘IO或者网络数据时,操作系统会切换到其他线程继续工作,这时原来的线程就处于阻塞状态。而协程则可以主动放弃控制权,转而执行其他的协程任务,这就避免了因为等待资源造成的阻塞,提高了程序的运行效率。

控制:由于线程的调度由操作系统自动完成,程序对其具体的执行流程控制较弱。而协程由程序自身控制其切换,因此程序对协程的控制更为精确。

线程可以同时多个运行,协程在任意时刻只能运行一个,其他处于暂停状态。

协程简单示例

Python中的协程示例:

import asyncio

async def count():
    print("One")
    await asyncio.sleep(1)
    print("Two")

async def main():
    await asyncio.gather(count(), count(), count())

asyncio.run(main())

这个示例中,我们创建了一个名为count的协程。这个协程先打印"one",然后等待1秒,再打印"Two"。注意到await关键字,它告诉Python暂停执行count协程,转而去执行其他的任务,在这里就是等待1秒。过了1秒之后,Python会回到被暂停的count协程,继续执行,打印出"Two"。

main协程中,我们用到了asyncio.gather函数,并同时运行了三个count协程。如果没有用到协程,程序打印One和Two之间都需要等待1秒。但是在这个例子中,程序会先打印出三个"One",然后等待1秒,再打印出三个"Two"。

asyncio.run(main())这行代码就是启动整个程序。

可以看到,通过使用协程,我们的程序可以在等待某个任务完成的期间,并发地执行其他的任务,提高了程序的效率。这就体现了协程的重要价值之一。


问题

线程可以同时多个运行,协程在任意时刻只能运行一个,为什么说上面的例子中同时运行了三个count协程?

在回答这个问题之前,我们首先需要明确一点,即协程虽然在任意时刻只能运行一个,但是可以在任何一个协程中主动放弃执行权,将控制权交回给主调度程序(在Python中通常是某种事件循环,如 asyncio.get_event_loop()),然后主调度程序再根据一定的规则选择下一个协程执行。

特别地,当一个协程遇到IO等待(比如网络请求、磁盘读写等)的时候,它会主动放弃执行权,这样主调度程序就可以在一个协程等待的时候执行其他协程,从而实现了并发。

'asyncio.gather(count(), count(), count())'是并发地运行三个 count 协程。这并不是说这三个协程真正意义上并行(同时)运行,而是说明:当一个 count 协程执行到 ‘await asyncio.sleep(1)’ 这行代码时,会主动放弃执行权,然后事件循环就去执行下一个还未进入睡眠的 count 协程,这样循环下去就实现了这三个 count 协程的并发。

因此,我们看到"程序会先打印出三个’One’,然后等待1秒,再打印出三个’Two’"其实就是Python的协程调度机制执行的结果。每个count协程在执行到 ‘await asyncio.sleep(1)’ 这行代码后,由于’await’关键字的存在,都会主动放弃执行权,然后执行下一个 count 协程,当所有的 count 协程都放弃了执行权进入了睡眠后,主调度程序(事件循环)就静静等待一秒,一秒后再唤醒这三个 ‘count’ 协程,继续执行它们之后的代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

safina ~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值