教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 Golang协程原理(一)

Golang协程原理(一)

发布时间:2021-05-18   编辑:jiaochengji.com
教程集为您提供Golang协程原理(一)等资源,欢迎您收藏本站,我们将为您提供最新的Golang协程原理(一)资源

转自:https://studygolang.com/articles/9592?p=1

协程是应用层的线程

 应用层是相对于内核层而言,是操作系统的概念,对应的是cpu的运行级别。操作系统的核心代码运行的ring0级别,应用程序的代码运行在ring3级别。内核与应用层的级别设置保证了一些高权限的操作只有内核代码能做,应用程序要使用这些功能必须通过调用操作系统的API(linux上称为系统调用)来调用内核的代码。这个调用会导致cpu从ring3到ring0的上下文切换,这个切换是耗费一些cpu时间的。
 
线程是操作系统的内核对象,多线程编程时,如果线程数过多,就会导致频繁的上下文切换,这些cpu时间是一个额外的耗费。所以在一些高并发的网络服务器编程中,使用一个线程服务一个socket连接是很不明智的。于是操作系统提供了基于事件模式的异步编程模型。用少量的线程来服务大量的网络连接和I/O操作。但是采用异步和基于事件的编程模型,复杂化了程序代码的编写,非常容易出错。因为线程穿插,也提高排查错误的难度。
 
协程,是在应用层模拟的线程,它避免了上下文切换的额外耗费,兼顾了多线程的优点。简化了高并发程序的复杂度。举个例子,一个高并发的网络服务器,每一个socket连接进来,服务器用一个协程来对它进行服务。代码非常清晰。而且兼顾了性能。

协程是怎么实现的呢

它和线程的原理是一样的,当a线程切换到b线程的时候,需要将a线程的相关执行进度压入栈,然后将b线程的执行进度出栈,进入b的执行序列。协程只不过是在应用层实现这一点。
但是,协程并不是由操作系统调度的,而且应用程序也没有能力和权限执行cpu调度。怎么解决这个问题?
答案是,协程是基于线程的。内部实现上,维护了一组数据结构和n个线程,真正的执行还是线程,协程执行的代码被扔进一个待执行队列中,有这n个线程从队列中拉出来执行。这就解决了协程的执行问题。那么协程是怎么切换的呢?答案是:golang对各种io函数进行了封装,这些封装的函数提供给应用程序使用,而其内部调用了操作系统的异步io函数,当这些异步函数返回busy或bloking时,golang利用这个时机将现有的执行序列压栈,让线程去拉另外一个协程的代码来执行,基本原理就是这样,利用并封装了操作系统的异步函数。包括linux的epoll,select和windows的iocp,event等。
 
由于golang是从编译器和语言基础库多个层面对协程做了实现,所以,golang的协程是目前各类有协程概念的语言中实现的最完整和成熟的。
十万个协程同时运行也毫无压力。关键我们不会这么写代码。但是总体而言,程序员可以在编写golang的代码是,可以更多的关注业务逻辑的实现,更少的在这些关键的基础构件上耗费太多精力。

到此这篇关于“Golang协程原理(一)”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
golang channel的使用以及调度原理
Go语言之goroutine协程详解
探索Golang协程实现——从v1.0开始
go 协程
Go语言学习笔记七(协程)
让你很快就能理解-go的协程调度原理
Golang教程:goroutine协程
Golang协程原理(一)
golang的协程原理
从零学习 Go 语言(24):理解 Go 语言中的 goroutine

[关闭]
~ ~