


Eine vorläufige Untersuchung von Goroutine und Channel in der Go-Sprache
Dieser Artikel wird Ihnen ein erstes Verständnis von Goroutine und Channel in der Go-Sprache vermitteln. Ich hoffe, er wird Ihnen hilfreich sein!
Die Implementierung des CSP
-Parallelitätsmodells der Go-Sprache enthält zwei Hauptkomponenten: eine ist Goroutine
und die andere ist channel
. In diesem Artikel werden ihre grundlegende Verwendung und Vorsichtsmaßnahmen vorgestellt. CSP
并发模型的实现包含两个主要组成部分:一个是 Goroutine
,另一个是 channel
。本文将会介绍它们的基本用法和注意事项。
Goroutine
Goroutine
是 Go
应用的基本执行单元,它是一种轻量的用户级线程,其底层是通过 coroutine
(协程)去实现的并发。众所周知,协程是一种运行在用户态的用户线程,因此 Goroutine
也是被调度于 Go
程序运行时。
基本用法
语法:go + 函数/方法
通过 go 关键字 + 函数/方法 可以创建一个 Goroutine
。
代码示例:
import ( "fmt" "time" ) func printGo() { fmt.Println("具名函数") } type G struct { } func (g G) g() { fmt.Println("方法") } func main() { // 基于具名函数创建 goroutine go printGo() // 基于方法创建 goroutine g := G{} go g.g() // 基于匿名函数创建 goroutine go func() { fmt.Println("匿名函数") }() // 基于闭包创建 goroutine i := 0 go func() { i++ fmt.Println("闭包") }() time.Sleep(time.Second) // 避免 main goroutine 结束后,其创建的 goroutine 来不及运行,因此在此休眠 1 秒 }
执行结果:
闭包 具名函数 方法 匿名函数
当多个 Goroutine
存在时,它们的执行顺序是不固定的。因此每次打印的结果都不相同。
由代码可知,通过 go
关键字,我们可以基于 具名函数 / 方法 创建 goroutine
,也可以基于 匿名函数 / 闭包 创建 goroutine
。
那么 Goroutine
是如何退出的呢?正常情况下,只要 Goroutine
函数执行结束,或者执行返回,意味着 Goroutine
的退出。如果 Goroutine
的函数或方法有返回值,在 Goroutine
退出时会将其忽略。
channel
channel
在 Go 并发模型中扮演者重要的角色。它可以用于实现 Goroutine
间的通信,也可以用来实现 Goroutine
间的同步。
channel 的基本操作
channel
是一种复合数据类型,声明时需要指定 channel
里元素的类型。
声明语法:var ch chan string
通过上述代码声明一个元素类型为 string
的 channel
,其只能存放 string
类型的元素。channel
是引用类型,必须初始化才能写入数据,通过 make
的方式初始化。
import ( "fmt" ) func main() { var ch chan string ch = make(chan string, 1) // 打印 chan 的地址 fmt.Println(ch) // 向 ch 发送 "Go" 数据 ch <- "Go" // 从 ch 中接收数据 s := <-ch fmt.Println(s) // Go }
通过 ch <- xxx
可以向 channel
变量 ch
发送数据,通过 x := <- ch
可以从 channel
变量 ch
中接收数据。
带缓冲 channel 与无缓冲 channel
如果初始化 channel
时,不指定容量时,则创建的是一个无缓冲的 channel
:
ch := make(chan string)
无缓冲的 channel
的发送与接收操作是同步的,在执行发送操作之后,对应 Goroutine
将会阻塞,直到有另一个 Goroutine
去执行接收操作,反之亦然。如果将发送操作和执行操作放在同一个 Goroutine 下进行,会发生什么操作呢?看看下述代码:
import ( "fmt" ) func main() { ch := make(chan int) // 发送数据 ch <- 1 // fatal error: all goroutines are asleep - deadlock! // 接收数据 n := <-ch fmt.Println(n) }
程序运行之后,会在 ch <-
处得到 fatal error
,提示所有的 Goroutine
处于休眠状态,也就是死锁了。为避免这种情况,我们需要将 channel
的发送操作和接收操作放到不同的 Goroutine
中执行。
import ( "fmt" ) func main() { ch := make(chan int) go func() { // 发送数据 ch <- 1 }() // 接收数据 n := <-ch fmt.Println(n) // 1 }
由上述例子可以得出结论:无缓冲 channel
的发送与接收操作,一定要放在两个不同的 Goroutine
中进行,否则会发生 deadlock
形象。
如果指定容量,则创建的是一个带缓冲的 channel
:
ch := make(chan string, 5)
有缓冲的 channel
与无缓冲的 chennel
有所区别,执行发送操作时,只要 channel
的缓冲区未满,Goroutine
不会挂起,直到缓冲区满时,再向 channel
执行发送操作,才会导致 Goroutine
挂起。代码示例:
func main() { ch := make(chan int, 1) // 发送数据 ch <- 1 ch <- 2 // fatal error: all goroutines are asleep - deadlock! }
声明 channel 的只发送类型和只接收类型
既能发送又能接收的
channel
ch := make(chan int, 1)
Nach dem Login kopieren通过上述代码获得
channel
变量,我们可以对它执行发送与接收的操作。只接收的
channel
ch := make(<-chan int, 1)
Nach dem Login kopieren通过上述代码获得
channel
变量,我们只能对它进行接收操作。只发送的
channel
ch := make(chan<- int, 1)
Nach dem Login kopieren通过上述代码获得
channel
Goroutine
Goroutine
ist die grundlegende Ausführungseinheit derGo
-Anwendung Es handelt sich um einen leichten Thread auf Benutzerebene, dessen zugrunde liegende Ebene durchcoroutine
(coroutine) implementiert wird. Wie wir alle wissen, ist eine Coroutine ein Benutzerthread, der im Benutzermodus ausgeführt wird. Daher wirdGoroutine
auch geplant, wenn das ProgrammGo
ausgeführt wird. 🎜Grundlegende Verwendung
🎜Syntax: go + Funktion/Methode 🎜
🎜By go Schlüsselwort + Funktion/Methode kann eineGoroutine
erstellen. 🎜🎜Codebeispiel: 🎜🎜Ausführungsergebnis: 🎜func send(ch chan<- int) { ch <- 1 } func recv(ch <-chan int) { <-ch }
Nach dem Login kopierenNach dem Login kopieren🎜Wenn mehrerefunc main() { ch := make(chan int, 5) ch <- 1 close(ch) ch <- 2 // panic: send on closed channel }
Nach dem Login kopierenNach dem Login kopierenGoroutine
vorhanden sind, ist ihre Ausführungsreihenfolge nicht festgelegt. Daher sind die Ergebnisse bei jedem Ausdruck unterschiedlich. 🎜🎜Wie aus dem Code ersichtlich ist, können wir mit dem Schlüsselwortgo
goroutine
basierend auf benannter Funktion/Methode< erstellen /strong>, auchgoroutine
kann basierend auf anonymer Funktion / closure erstellt werden. 🎜🎜Wie wirdGoroutine
beendet? Unter normalen Umständen bedeutet dies, dassGoroutine
beendet wird, solange die Ausführung der FunktionGoroutine
endet oder die Ausführung zurückkehrt. Wenn die Funktion oder Methode vonGoroutine
einen Rückgabewert hat, wird dieser ignoriert, wennGoroutine
beendet wird. 🎜channel
🎜channel
spielt eine wichtige Rolle im Go-Parallelitätsmodell. Es kann zum Implementieren der Kommunikation zwischenGoroutine
und auch zum Implementieren der Synchronisierung zwischenGoroutine
verwendet werden. 🎜Grundfunktionen des Kanals
🎜channel
ist ein zusammengesetzter Datentyp undchannel
. 🎜🎜Deklarationssyntax: var ch chan string🎜
🎜Deklarieren Sie einenKanal
, dessen Elementtypstring
ist, über den obigen Code, der nur < speichern kann code Elemente vom Typ >string.channel
ist ein Referenztyp und muss initialisiert werden, bevor Daten geschrieben werden können. Die Initialisierung erfolgt übermake
. 🎜🎜Sie können Daten an dieimport "fmt" func main() { ch := make(chan int, 5) ch <- 1 close(ch) fmt.Println(<-ch) // 1 n, ok := <-ch fmt.Println(n) // 0 fmt.Println(ok) // false }
Nach dem Login kopierenNach dem Login kopierenchannel
-Variablech
überch <- xxx
und überx := < senden. - ch< /code> kann Daten von der <code>channel
-Variablech
empfangen. 🎜Gepufferter Kanal und ungepufferter Kanal
🎜Wenn die Kapazität bei der Initialisierung vonchannel
nicht angegeben wird, dann Was ist Es wird ein ungepufferterKanal
erstellt: 🎜rrreee🎜Die Sende- und Empfangsvorgänge des ungepuffertenKanals
sind synchron. Nachdem der Sendevorgang ausgeführt wurde, wird die entsprechendeGoroutine </ erstellt. code> blockiert, bis eine andere <code>Goroutine
verfügbar ist, um den Empfangsvorgang auszuführen, und umgekehrt. Was passiert, wenn der Sendevorgang und der Ausführungsvorgang unter derselben Goroutine platziert werden? Schauen Sie sich den folgenden Code an: 🎜rrreee🎜Nachdem das Programm ausgeführt wurde, wird beich <-
einschwerwiegender Fehler
angezeigt, der dazu führt, dass alleGoroutine< /code> befinden sich im Ruhezustand, d. h. im Deadlock-Zustand. Um diese Situation zu vermeiden, müssen wir die Sende- und Empfangsvorgänge von <code>channel
in verschiedenenGoroutine
ausführen. 🎜rrreee🎜Aus dem obigen Beispiel kann geschlossen werden: Die Sende- und Empfangsvorgänge des ungepuffertenKanals
müssen in zwei verschiedenenGoroutinen
ausgeführt werden, andernfalls < code>Deadlock Code> Bild. 🎜
🎜Wenn die Kapazität angegeben wird, wird ein gepufferterchannel
erstellt: 🎜rrreee🎜Gepufferterchannel
und ungepufferterchennel
sind unterschiedlich. Bei der Ausführung eines Sendevorgangs bleibtGoroutine
erst dann hängen, wenn der Puffer vonchannel
voll ist. Nur wenn >channel ausgeführt wird Ein Sendevorgang führt dazu, dassGoroutine
hängen bleibt. Codebeispiel: 🎜rrreeeDeklarieren Sie den Nur-Sende-Typ und den Nur-Empfangs-Typ des Kanals
- 🎜Can sowohl senden als auch empfangen Der empfangene
channel
🎜rrreee🎜 erhält die Variablechannel
über den obigen Code, und wir können darauf Sende- und Empfangsvorgänge ausführen. 🎜 - 🎜Nur Empfang von
channel
🎜rrreee🎜Die Variablechannel
wird über den obigen Code abgerufen und wir können nur Empfangsvorgänge für sie ausführen. 🎜 - 🎜Nur der sendende
channel
🎜rrreee🎜erhält die Variablechannel
über den obigen Code, und wir können ihn nur senden. 🎜
通常只发送
channel
类型和只接收channel
类型,会被用作函数的参数类型或返回值:func send(ch chan<- int) { ch <- 1 } func recv(ch <-chan int) { <-ch }
Nach dem Login kopierenNach dem Login kopierenchannel 的关闭
通过内置函
close(c chan<- Type)
,可以对channel
进行关闭。在发送端关闭
channel
在
channel
关闭之后,将不能对channel
执行发送操作,否则会发生panic
,提示channel
已关闭。func main() { ch := make(chan int, 5) ch <- 1 close(ch) ch <- 2 // panic: send on closed channel }
Nach dem Login kopierenNach dem Login kopieren管道
channel
之后,依旧可以对channel
执行接收操作,如果存在缓冲区的情况下,将会读取缓冲区的数据,如果缓冲区为空,则获取到的值为channel
对应类型的零值。import "fmt" func main() { ch := make(chan int, 5) ch <- 1 close(ch) fmt.Println(<-ch) // 1 n, ok := <-ch fmt.Println(n) // 0 fmt.Println(ok) // false }
Nach dem Login kopierenNach dem Login kopieren如果通过 for-range 遍历
channel
时,中途关闭channel
则会导致for-range
循环结束。
小结
本文首先介绍了
Goroutine
的创建方式以及其退出的时机是什么。其次介绍了如何创建
channel
类型变量的有缓冲与无缓冲的创建方式。需要注意的是,无缓冲的channel
发送与接收操作,需要在两个不同的Goroutine
中执行,否则会发送error
。接下来介绍如何定义只发送和只接收的
channel
类型。通常只发送channel
类型和只接收channel
类型,会被用作函数的参数类型或返回值。最后介绍了如何关闭
channel
,以及关闭之后的一些注意事项。Das obige ist der detaillierte Inhalt vonEine vorläufige Untersuchung von Goroutine und Channel in der Go-Sprache. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!
- 🎜Can sowohl senden als auch empfangen Der empfangene

Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

AI Hentai Generator
Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

Heiße Werkzeuge

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Heiße Themen



In der Bibliothek, die für den Betrieb der Schwimmpunktnummer in der GO-Sprache verwendet wird, wird die Genauigkeit sichergestellt, wie die Genauigkeit ...

Das Problem der Warteschlange Threading In Go Crawler Colly untersucht das Problem der Verwendung der Colly Crawler Library in Go -Sprache. Entwickler stoßen häufig auf Probleme mit Threads und Anfordern von Warteschlangen. � ...

Zwei Möglichkeiten, Strukturen in der GO -Sprache zu definieren: Der Unterschied zwischen VAR- und Typ -Schlüsselwörtern. Bei der Definition von Strukturen sieht die Sprache oft zwei verschiedene Schreibweisen: Erstens ...

Der Unterschied zwischen Stringdruck in GO -Sprache: Der Unterschied in der Wirkung der Verwendung von Println und String () ist in Go ...

Welche Bibliotheken in GO werden von großen Unternehmen oder bekannten Open-Source-Projekten entwickelt? Bei der Programmierung in Go begegnen Entwickler häufig auf einige häufige Bedürfnisse, ...

Was soll ich tun, wenn die benutzerdefinierten Strukturbezeichnungen in Goland nicht angezeigt werden? Bei der Verwendung von Goland für GO -Sprachentwicklung begegnen viele Entwickler benutzerdefinierte Struktur -Tags ...

Das Problem der Verwendung von RETISTREAM zur Implementierung von Nachrichtenwarteschlangen in der GO -Sprache besteht darin, die Go -Sprache und Redis zu verwenden ...

Automatische Löschung von Golang Generic -Funktionstypeinschränkungen in VSCODE -Benutzern kann auf ein seltsames Problem beim Schreiben von Golang -Code mit VSCODE stoßen. Wann...
