Golang中的协程(coroutine)概念,其名字来源可以从两个方面来解释,一是历史背景,二是技术特性。
历史背景
协程(coroutine)这个概念最早可以追溯到计算机科学的早期。它最初由Melvin Conway在1958年提出,并在1963年的论文中正式定义。协程是一种程序组件,它允许不同的入口点用于暂停和恢复执行,这种机制允许执行流在不同的协程之间切换,而不是传统的函数调用的方式。这种设计最初是为了在没有现代操作系统支持多任务的环境下,实现程序内部的并发执行。
技术特性
从技术特性上来说,“co-” 前缀在英语中常常表示“共同”,“routine” 则可以翻译为“常规程序”或“例程”。因此,“coroutine” 字面上可以理解为“共同的例程”,意味着它们是可以共享执行流程的例程,相互之间可以协作运行,而不是像传统的子程序(subroutine)那样,一个调用另一个时,被调用者必须完成执行后,控制权才返回给调用者。
在Golang中,协程被实现为“goroutine”,它是Go语言并发设计的核心。Goroutine在使用和概念上与传统的协程有所不同,但基本思想是相通的。Goroutine是由Go运行时(runtime)管理的轻量级线程,它们在Go程序中用于实现并发操作。使用goroutine时,开发者无需了解复杂的线程创建、同步和管理的细节,可以非常简单地启动成千上万的并发任务。
结合解释
因此,从历史和技术特性来看,Golang中的协程(goroutine)名字的来源,既体现了它作为一种允许多个入口点、可以相互协作的程序组件的历史背景,也反映了它在Go语言中作为实现并发编程的一种轻量级、高效的机制。
“协”是否可以代表为用户态调度是协作式的
在协程(coroutine)的上下文中,“协”是可以理解为协作式的(cooperative),特别是在强调与用户态调度相对应的场景中。这种协作式调度与抢占式调度(preemptive scheduling)形成对比,后者是操作系统内核对线程的调度方式。
协作式调度
在协作式调度中,每个任务(在这里指协程)自行决定何时让出CPU给其他任务运行。这意味着一个运行中的协程会一直执行,直到它显式地表示要让出执行权(例如,通过等待I/O操作、显式挂起或调用其他协程等方式)。这种方式的优点是上下文切换开销小,因为切换发生的时机是可预测的,并且由协程自己控制。但缺点是,如果一个协程长时间占用CPU不主动让出执行权,会导致其他协程饿死,影响程序的响应性。
抢占式调度
相对地,抢占式调度由操作系统内核控制,操作系统会根据一定的策略(如时间片轮转)强制从当前运行的线程中夺取CPU控制权,并分配给另一个线程。这种方式可以保证所有线程都能获得执行的机会,提高系统的响应性和公平性,但上下文切换的开销相对较大。
Golang中的Goroutine
在Golang中,goroutine虽然在用户态实现,但Go运行时(runtime)对它们有一定的调度策略,使得它们看起来更像是被“协作式”调度。然而,Go运行时也会在必要时进行调度决策(如GOMAXPROCS参数控制的系统线程数量),在一定程度上介于纯粹的协作式和抢占式调度之间。这种设计使得goroutine能够高效地利用多核处理器,同时保持使用上的简单性。
因此,“协”在协程中确实可以理解为强调了协作式的调度方式,这是区别于传统线程抢占式调度的一个重要特点。