Coroutine,翻译成”协程“,初始碰到的人马上就会跟进程和线程两个概念联系起来。直接先说区别,Coroutine是编译器级的,Process和Thread是操作系统级的。Coroutine的实现,通常是对某个语言做相应的提议,然后通过后成编译器标准,然后编译器厂商来实现该机制。Process和Thread看起来也在语言层次,但是内生原理却是操作系统先有这个东西,然后通过一定的API暴露给用户使用,两者在这里有不同。Process和Thread是os通过调度算法,保存当前的上下文,然后从上次暂停的地方再次开始计算,重新开始的地方不可预期,每次CPU计算的指令数量和代码跑过的CPU时间是相关的,跑到os分配的cpu时间到达后就会被os强制挂起。Coroutine是编译器的魔术,通过插入相关的代码使得代码段能够实现分段式的执行,重新开始的地方是yield关键字指定的,一次一定会跑到一个yield对应的地方。
对于操作系统来说,协程其实是一种特殊的线程,对于CPU来说,协程是非抢占式(进程和线程是抢占式的),实现机理如下:
有两个function:A, B, A调用B,B要执行一段时间,很晚才返回,A不会因为等B而一直占用CPU,即A是非阻塞的。B返回后,A又能继续执行。神奇的是,A和B又是走在一条独木桥(桥上并行只能走一条线程或者进程)上的,即A和B是一体的(和线程,进程同一级别)。那么有人会问,B要执行很久,B不就阻塞了吗,既然AB一体,B阻塞,不就是A阻塞吗?重要的来了:B是阻塞的,但是B并不是阻塞CPU,B阻塞的是除了CPU以外的资源,比如硬盘(慢)。所以,AB并不会阻塞CPU。这里,AB就是协程。
比较一下线程,又有两个function:C,D,C执行很快,D要去读硬盘,那么如果CD一体,是一个线程,那么C一定会等D(因为线程是CPU抢占式的),那么CD就是堵塞的了。
所以,可以看到,协程适合用在多IO,比如Web后台,每个用户来了都要读数据库,我们不能让每个用户来到离开一直占领着CPU,这时候用协程就解决了。
这时,又有人说了,可以用多线程来实现AB啊。是可以,但是多线程就涉及到共享冲突的问题,最经典的是生产者消费者模型。
我们来对比一下python的多线程和goroutine
python的多线程是伪多线程不能使用多核,go使用runtime.GOMAXPROCS(1) 只使用单核
开两个线程或者携程分别打印a-z,A-Z
python:
#-*- encoding: utf-8 -*-
import threading
class TestA(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
for i in xrange(26):
print chr(i + ord('A'))
class Testa(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
for i in xrange(26):
print chr(i + ord('a'))
if __name__ == '__main__':
threads = []
# 创建线程对象
threads.append(TestA())
threads.append(Testa())
# 启动线程
for t in threads:
t.start()
# 等待子线程结束
for t in threads:
t.join()
打印无顺序。
go:
package main
import (
"fmt"
"runtime"
"sync"
)
func main() {
runtime.GOMAXPROCS(1)
var wg sync.WaitGroup
wg.Add(2)
fmt.Println("Start Goroutines")
go func() {
defer wg.Done()
for char := 'a'; char < 'a'+26; char++ {
fmt.Printf("%c", char)
}
}()
go func() {
defer wg.Done()
for char := 'A'; char < 'A'+26; char++ {
fmt.Printf("%c", char)
}
}()
fmt.Println("Waiting To Finish")
wg.Wait()
fmt.Println("\nTerminating Program")
}
Start Goroutines
Waiting To Finish
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
Terminating Program