如果了解一些操作系统的相关知识的话,我们应该知道:进程是资源分配的最小单位,线程是CPU调度的最小单位。
(这里的CPU,指的是一个CPU逻辑核。因为一台主机可能有多个CPU,一个CPU可能有多个核心,CPU可能还支持超线程。)
从进程和线程的角度而言,后台服务程序可以有四种模型: 单进程单线程模型,单进程多线程模型,多进程单线程模型,多进程多线程模型。
通常,一个传统的后台服务程序采用多进程多线程模型(至于为什么,不在本文讨论范围)。有少数几个进程,其中可能有一个master进程用来管理整个程序,一个proxy进程用来代理转发报文给其他进程,然后有一个worker进程来处理实际业务。worker进程通常是多线程的。
传统的多线程模型存在以下不足:
简单的说就是,多线程模型在性能上不够优,而且实现的时候会有很多额外的工作量。
协程在一定程度上解决的这些问题,它基本可以实现多线程模型的效果,又不需要考虑锁、同步等问题。
协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
以下是来自wikepedia的介绍:
Coroutines are computer-program components that generalize subroutines for non-preemptive multitasking, by allowing multiple entry points for suspending and resuming execution at certain locations. 协同程序是计算机程序组件,它通过允许多个入口点在某些位置暂停和恢复执行来概括用于非抢占式多任务的子程序。
在协程中,一个线程里会有多个子程序(任务),这些子程序可以协同合作,看起来就像多个线程一样。然而,我们说线程才是CPU调度的基本单位,不进行CPU到底如何实现多任务呢,前面已经说过,是通过设置一些暂定和恢复子程序执行的入口点实现的。
协程拥有自己的寄存器上下文和栈,协程中的子程序有点类似于函数调用。但是函数调用只有一个入口,且退出后下次调用就需要从头开始执行。而协程允许在子程序的中间多个位置暂定和恢复执行。
下面利用C中的goto,实现一个简单的协程模型:
#include <stdio.h>
int main()
{
int line;
{ // 子程序1
for (int i=0; i < 10; i++) {
goto coroutine2;
coroutine1:
printf("coroutine 1: %d\n", i);
}
}
{ //子程序2
for (int j=0; j < 10; j++) {
goto coroutine1;
coroutine2:
printf("coroutine 2: %d\n", j);
}
}
return 0;
}
子程序1和子程序2可以像线程那样交替执行,由于两个子程序在同一个函数中,变量i和j的栈空间没有被销毁,而不需保存上下文。
也可以通过setjmp和longjmp来实现用单独函数表示子程序的协程模型。
以上只是通过模型来简单介绍协程的原理,实际应用中可能是通过汇编或其他更精妙的方式来实现协程。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。