以下这些是个人对于协程的总结。
先说一下协程的优点:
● 协程的最大的优势:协程切换开销远小于线程,进程切换。相比于线程,协程没有内核态的上下文切换,近乎可以无限并发。协程在用户态进程显式的调度,可以把异步操作转换为同步操作,也意味着不需要加锁,避免了加锁过程中不必要的开销。Golang为什么有这么强的并发能力,协程居功至伟。协程创建于用户空间,理论上可以创建的协程数量远大于线程。
● 引入协程库后,代码以顺序性书写,易于理解,而执行时则是异步调用,性能不减。
使用协程需要注意的地方:
● 使用协程并不简单,在处理IO时,需要对IO函数进行封装,使之支持异步唤醒机制。例如Cyber RT的Schduler框架和微信的libco。
● 同一个线程内的任何一个协程不能发生阻塞,否则将阻塞所有相关协程。线程则没有这个问题。也就是说不要在协程中执行耗时的操作。
下面贴一下Cyber RT用协程处理IO的时序图:
在图中蓝圈处,用户主线程通过RoutineFactory和Schduler注册了两个协程回调函数。 Transport层(线程)接收到数据后,通过回调将数据填充到相关缓存中,并进行融合。然后通过Schduler唤醒之前注册的两个协程(图中红圈),并进行后续处理。协程是在Schduler框架中的Processor线程里执行。注意文中提到的三个线程。
需要说明的是,协程主要解决两个问题,高并发和应用层调度(优先级)。自动驾驶不同于WEB系统,并发量并不是特别大,这方面能带来的性能提升并不显著。自动驾驶对实时性要求较高,而使用得最多的操作系统是Linux,但它并不是一个实时操作系统,操作系统API提供的保证实时性的手段有限,改造操作系统也不现实。通过引入协程,可以更方便地对任务建立优先级,提高实时响应。Cyber RT引入协程的主要目的并不是为了提高并发量,而是为了实现用户空间的调度策略,设置任务优先级和CPU亲和性,以提高实时性。