引言
基础知识
如果了解一些操作系统的相关知识的话, 我们应该知道: 进程是资源分配的最小单位, 线程是 CPU 调度的最小单位.
(这里的 CPU, 指的是一个 CPU 逻辑核. 因为一台主机可能有多个 CPU, 一个 CPU 可能有多个核心, CPU 可能还支持超线程.)
从进程和线程的角度而言, 后台服务程序可以有四种模型: 单进程单线程模型, 单进程多线程模型, 多进程单线程模型, 多进程多线程模型.
通常, 一个传统的后台服务程序采用多进程多线程模型 (至于为什么, 不在本文讨论范围). 有少数几个进程, 其中可能有一个 master 进程用来管理整个程序, 一个 proxy 进程用来代理转发报文给其他进程, 然后有一个 worker 进程来处理实际业务. worker 进程通常是多线程的.
传统模型的缺陷
传统的多线程模型存在以下不足:
线程锁: 由于进程才是资源分配的基本单位, 不同线程会产生资源竞争的场景, 因此需要通过线程锁来保证线程安全. 锁的使用需要及其小心.
同步: 不同的线程经常存在需要同步结果的场景. 这可能需要借助 semaphore,event,join 等工具, 而且可能还需要有一个线程阻塞来处理其它线程的同步结果.
性能: 多线程会产生 CPU 调度, CPU 调度是有开销的.
简单的说就是, 多线程模型在性能上不够优, 而且实现的时候会有很多额外的工作量.
协程在一定程度上解决的这些问题, 它基本可以实现多线程模型的效果, 又不需要考虑锁, 同步等问题.
协程
协程是什么
协程是一种用户态的轻量级线程, 协程的调度完全由用户控制. 协程拥有自己的寄存器上下文和栈. 协程调度切换时, 将寄存器上下文和栈保存到其他地方, 在切回来的时候, 恢复先前保存的寄存器上下文和栈, 直接操作栈则基本没有内核切换的开销, 可以不加锁的访问全局变量, 所以上下文的切换非常快.
以下是来自 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.
协同程序是计算机程序组件, 它通过允许多个入口点在某些位置暂停和恢复执行来概括用于非抢占式多任务的子程序.
- #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;
- }
来源: https://www.qcloud.com/developer/article/1159464