搜尋
首頁後端開發Golanggo語言協程是什麼
go語言協程是什麼Dec 16, 2022 pm 02:27 PM
gogolanggo語言協程

在go语言中,协程(goroutine)是指在后台中运行的轻量级执行线程;go协程是Go中实现并发的关键组成部分。Go中提供了一个关键字go来创建一个Go协程,当在函数或方法的调用之前添加一个关键字go,这样就开启了一个Go协程,该函数或者方法就会在这个Go协程中运行。

go語言協程是什麼

本教程操作环境:windows7系统、GO 1.18版本、Dell G3电脑。

Go 协程 (goroutine) 是指在后台中运行的轻量级执行线程,go 协程是 Go 中实现并发的关键组成部分。

由于 Go 协程相对于传统操作系统中的线程 (thread) 是非常轻量级的,因此对于一个典型的 Go 应用来说,有数以千计的 Go 协程并发运行的情形是十分常见的。并发可以显著地提升应用的运行速度,并且可以帮助我们编写关注点分离(Separation of concerns,Soc)的代码。

什么是 Go 协程?

我们也许在理论上已经知晓 Go 协程是如何工作的,但是在代码层级上,go 协程何许物也?其实,go 协程看起来只是一个与其他众 Go 协程并发运行的一个简单函数或者方法,但是我们并不能想当然地从函数或者方法中的定义来确定一个 Go 协程,go 协程的确定还是要取决于我们如何去调用。【相关推荐:Go视频教程编程教学

Go 中提供了一个关键字 go 来让我们创建一个 Go 协程,当我们在函数或方法的调用之前添加一个关键字 go,这样我们就开启了一个 Go 协程,该函数或者方法就会在这个 Go 协程中运行。

举个简单的栗子:

go語言協程是什麼

play.golang.org/p/pIGsT

在上面的代码中,我们定义了一个可以在控制台输出 Hello World 字符串的 printHello 的函数,在 main 函数中,我们就像平时那样调用 printHello 函数,最终也是理所当然地获得了期望的结果。

下面,让我们尝试从同一个函数创建 Go 协程:

go語言協程是什麼

play.golang.org/p/LWXAg

根据 Go 协程的语法,我们在函数调用的前面增加了一个 go 关键字,之后程序运行正常,输出了以下的结果:

main execution started
main execution stopped

奇怪的是,Hello World 并没有如同我们预料的那样输出,这期间究竟发生了什么?

go 协程总是在后台运行,当一个 Go 协程执行的时候(在这个例子中是 go printHello()), Go 并不会像在之前的那个例子中在执行 printHello 中的功能时阻塞 main 函数中剩下语句的执行,而是直接忽略了 Go 协程的返回并继续执行 main 函数剩下的语句。即便如此,我们为什么没法看到函数的输出呢?

在默认情况下,每个独立的 Go 应用运行时就创建了一个 Go 协程,其 main 函数就在这个 Go 协程中运行,这个 Go 协程就被称为 go 主协程(main Goroutine,下面简称主协程)。在上面的例子中,主协程 中又产生了一个 printHello 这个函数的 Go 协程,我们暂且叫它 printHello 协程 吧,因而我们在执行上面的程序的时候,就会存在两个 Go 协程(mainprintHello)同时运行。正如同以前的程序那样,go 协程们会进行协同调度。因此,当 主协程 运行的时候,Go 调度器在 主协程 执行完之前并不会将控制权移交给 printHello 协程。不幸的是,一旦 主协程 执行完毕,整个程序会立即终止,调度器再也没有时间留给 printHello 协程 去运行了。

但正如我们从其他课程所知,通过阻塞条件,我们可以手动将控制权转移给其他的 Go 协程 , 也可以说是告诉调度器让它去调度其他可用空闲的 Go 协程。让我们调用 time.Sleep() 函数去实现它吧。

go語言協程是什麼

play.golang.org/p/ujQKj

如上图所示,我们修改了程序,程序在 main 函数的最后一条语句之前调用了 time.Sleep(10 * time.Millisecond),使得 主协程 在执行最后一条指令之前调度器就将控制权转移给了 printhello 协程。在这个例子中,我们通过调用 time.Sleep(10 * time.Millisecond) 强行让 主协程 休眠 10ms 并且在在这个 10ms 内不会再被调度器重新调度运行。

一旦 printHello 协程 执行,它就会向控制台打印‘ Hello World !’,然后该 Go 协程(printHello 协程)就会随之终止,接下来 主协程 就会被重新调度(因为 main Go 协程已经睡够 10ms 了),并执行最后一条语句。因此,运行上面的程序就会得到以下的输出 :

main execution started
Hello World!
main execution stopped

下面我稍微修改一下例子,我在 printHello 函数的输出语句之前添加了一条 time.Sleep(time.Millisecond)。我们已经知道了如果我们在函数中调用了休眠(sleep)函数,这个函数就会告诉 Go 调度器去调度其他可被调度的 Go 协程。在上一课中提到,只有非休眠(non-sleeping)的 Go 协程才会被认为是可被调度的,所以主协程在这休眠的 10ms 内是不会被再次调度的。因此 主协程 先打印出“ main execution started ” 接着就创建了一个 printHello 协程,需要注意此时的 主协程 还是非休眠状态的,在这之后主协程就要调用休眠函数去睡 10ms,并且把这个控制权让出来给printHello 协程。printHello 协程会先休眠 1ms 告诉调度器看看有没有其他可调度的 Go 协程,在这个例子里显然没有其他可调度的 Go 协程了,所以在printHello协程结束了这 1ms 的休眠户就会被调度器调度,接着就输出了“ Hello World ”字符串,之后这个 Go 协程运行结束。之后,主协程会在之后的几毫秒被唤醒,紧接着就会输出“ main execution stopped ”并且结束整个程序。

go語言協程是什麼

play.golang.org/p/rWvzS

上面的程序依旧和之前的例子一样,输出以下相同的结果:

main execution started
Hello World!
main execution stopped

要是,我把这个printHello 协程中的休眠 1 毫秒改成休眠 15 毫秒,这个结果又是如何呢?

go語言協程是什麼

play.golang.org/p/Pc2nP

在这个例子中,与其他的例子最大的区别就是printHello 协程比主协程的休眠时间还要长,很明显,主协程要比 printHello 协程唤醒要早,这样的结果就是主协程即使唤醒后执行完所有的语句,printHello 协程还是在休眠状态。之前提到过,主协程比较特殊,如果主协程执行结束后整个程序就要退出,所以 printHello 协程得不到机会去执行下面的输出的语句了,所以以上的程序的数据结果如下:

main execution started
main execution stopped

使用多 Go 协程

就像之前我所提到过的,你可以随心所欲地创建多个 Go 协程。下面让我们定义两个简单的函数,一个是用于顺序打印某个字符串中的每个字符,另一个是顺序打印出某个整数切片中的每个数字。

go語言協程是什麼

play.golang.org/p/SJano

在上图中的程序中,我们连续地创建了两个 Go 协程,程序输出的结果如下:

main execution started
H e l l o 1 2 3 4 5
main execution stopped

上面的结果证实了 Go 协程是以合作式调度来运作的。下面我们在每个函数中的输出语句的下面添加一行 time.Sleep,让函数在输出每个字符或数字后休息一段时间,好让调度器调度其他可用的 Go 协程。

go語言協程是什麼

play.golang.org/p/lrSIE

在上面的程序中,我又修改了一下输出语句使得我们可以看到每个字符或数字的输出时刻。理论上主协程会休眠 200ms,因此其他 Go 协程要赶在主协程唤醒之前做完自己的工作,因为主协程唤醒之后就会导致程序退出。getChars 协程每打印一个字符就会休眠 10ms,之后控制权就会传给 getDigits 协程,getDigits 协程每打印一个数字后就休眠 30ms,若 getChars 协程唤醒,则会把控制权传回 getChars 协程,如此往复。在代码中可以看到,getChars 协程会在其他协程休眠的时候多次进行打印字符以及休眠操作,所以我们预计可以看到输出的字符比数字更具有连续性。

我们在 Windows 上运行上面的程序,得到了以下的结果:

main execution started at time 0s
H at time 1.0012ms                         <-|
1 at time 1.0012ms                           | almost at the same time
e at time 11.0283ms                        <-|
l at time 21.0289ms                          | ~10ms apart
l at time 31.0416ms
2 at time 31.0416ms
o at time 42.0336ms
3 at time 61.0461ms                        <-|
4 at time 91.0647ms                          |
5 at time 121.0888ms                         | ~30ms apart
main execution stopped at time 200.3137ms    | exiting after 200ms

通过以上输出结果可以证明我们之前对输出的讨论。对于这个结果,我们可以通过下面的的程序运行图来解释。需要注意的是,我们在图中定义一个输出语句大约会花费 1ms 的 CPU 时间,而这个时间相对于 200ms 来说是可以忽略不计的。

go語言協程是什麼

现在我们已经知道了如何去创建 Go 协程以及去如何去使用它。但是使用 time.Sleep 只是一个让我们获取理想结果的一个小技巧。在实际生产环境中,我们无法知晓一个 Go 协程到底需要执行多长的时间,因而在 main 函数里面添加一个 time.Sleep 并不是一个解决问题的方法。我们希望 Go 协程在执行完毕后告知主协程运行的结果。在目前阶段,我们还不知道如何向其他 Go 协程传递以及获取数据,简而言之,就是与其他 Go 协程进行通信。这就是 channels 引入的原因。我们会在下一次课中讨论这个东西。

匿名 Go 协程

如果一个匿名函数可以退出,那么匿名 Go 协程也同样可以退出。请参照<a href="https://www.php.cn/link/ebd7fd1c6f709ba1731266aa06dc8547" class=" wrap external" target="_blank" rel="nofollow noreferrer">functions</a> 课程中的 即时调用函数(Immedietly invoked function) 来理解本节。让我们修改一下之前 printHello 协程的例子:

go語言協程是什麼

结果非常明显,因为我们定义了匿名函数,并在同一语句中作为 Go 协程执行。

需要注意的是,所有的 Go 协程都是匿名的,因为我们从<a href="https://www.php.cn/link/91f598a719795f838bc589c49dd21462" class=" wrap external" target="_blank" rel="nofollow noreferrer">并发(concurrency</a> 一课中学到,go 协程是不存在标识符的,在这里所谓的匿名 Go 协程只是通过匿名函数来创建的 Go 协程罢了

更多编程相关知识,请访问:编程入门!!

以上是go語言協程是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
如何在PHP中使用协程?如何在PHP中使用协程?May 12, 2023 am 08:10 AM

随着传统的多线程模型在高并发场景下的性能瓶颈,协程成为了PHP编程领域的热门话题。协程是一种轻量级的线程,能够在单线程中实现多任务的并发执行。在PHP的语言生态中,协程得到了广泛的应用,比如Swoole、Workerman等框架就提供了对协程的支持。那么,如何在PHP中使用协程呢?本文将介绍一些基本的使用方法以及常见的注意事项,帮助读者了解协程的运作原理,以

如何在Swoole中使用协程实现高并发的swoole_smtp_auth函数如何在Swoole中使用协程实现高并发的swoole_smtp_auth函数Jun 25, 2023 am 08:28 AM

近年来,随着互联网应用的日益普及,各种高并发的场景也越来越常见。在这种情况下,传统的同步I/O方式已经无法满足现代应用对高性能、高并发的需求。因此,协程成为了一种被广泛应用的解决方案。Swoole是一款面向高并发、高性能的PHP网络通信框架,可以轻松实现异步、协程等特性。swoole_smtp_auth函数是其中一个常用的函数,它可以在使用SMTP协议进行邮

满满的干货!全面的介绍Python的协程是如何实现!看懂算你牛!满满的干货!全面的介绍Python的协程是如何实现!看懂算你牛!May 02, 2023 am 10:34 AM

如果你需要访问多个服务来完成一个请求的处理,比如实现文件上传功能时,首先访问Redis缓存,验证用户是否登录,再接收HTTP消息中的body并保存在磁盘上,最后把文件路径等信息写入MySQL数据库中,你会怎么做?首先可以使用阻塞API编写同步代码,直接一步步串行即可,但很明显这时一个线程只能同时处理一个请求。而我们知道线程数是有限制的,有限的线程数导致无法实现上万级别的并发连接,过多的线程切换也抢走了CPU的时间,从而降低了每秒能够处理的请求数量。于是为了达到高并发,你可能会选择一

Swoole进阶:如何使用协程优化数据库查询Swoole进阶:如何使用协程优化数据库查询Jun 15, 2023 pm 09:52 PM

随着Web应用程序的迅速发展,开发者们不仅要关注应用程序的功能和可靠性,还要考虑应用程序的性能。而数据库操作一直是Web应用程序的一个瓶颈之一。传统的数据库查询方式通常是通过多线程或者多进程来实现,这个方法效率低下,而且不容易管理。而Swoole的协程特性可以用来优化数据库查询,并提高应用程序的性能。Swoole是一款PHP的高性能网络框架。它有一个非常重要

Swoole新特性讲解:更快的高速协程HTTP服务器Swoole新特性讲解:更快的高速协程HTTP服务器Jun 15, 2023 pm 08:16 PM

近年来,随着移动互联网、云计算、大数据等新技术的快速发展,越来越多的企业开始使用PHP构建高并发、高性能的Web应用程序。而传统的LAMP(Linux、Apache、MySQL、PHP)架构,难以满足当前互联网快速发展的需求,因此出现了一些新的PHP框架和工具,比如Swoole。Swoole是一个PHP的网络通信框架,具有协程、异步IO、多进程等优势,可以帮

go语言中协程与线程的区别是什么go语言中协程与线程的区别是什么Feb 02, 2023 pm 06:10 PM

区别:1、一个线程可以多个协程,一个进程也可以单独拥有多个协程;2、线程是同步机制,而协程则是异步;3、协程能保留上一次调用时的状态,线程不行;4、线程是抢占式,协程是非抢占式的;5、线程是被分割的CPU资源,协程是组织好的代码流程,协程需要线程来承载运行。

Go 语言中的协程和 select 语句的联系是什么?Go 语言中的协程和 select 语句的联系是什么?Jun 10, 2023 am 09:45 AM

Go语言中的协程和select语句的联系是什么?随着计算机的发展,我们对于并发编程的需求也越来越迫切。然而,传统的并发编程方法——基于线程和锁——也逐渐变得复杂并容易出错。为了解决这些问题,Go语言引入了一种新的并发编程模型——协程。协程是由语言自己调度的轻量级线程,在协程中,代码的执行是基于非抢占式的协作式调度的,换句话说,每个协程都会执行一段代码

协程编程与Swoole实战:实现高并发接口设计协程编程与Swoole实战:实现高并发接口设计Jun 13, 2023 pm 06:39 PM

随着互联网应用的普及,越来越多的应用需要面对高并发的挑战。传统的线程池或进程池方式已经不能满足这种情况下的需求。协程编程技术成为了一种解决高并发问题的有效方式,而Swoole则是目前应用最广泛的协程框架之一。本文将介绍协程编程的基本概念和原理,以及如何使用Swoole框架进行高并发接口设计。我们将以一个简单的Web服务为例,分步骤介绍如何使用协程和Swool

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)