Go 언어의 고루틴과 채널에 대한 예비 탐색
이 글은 여러분에게 Go 언어의 고루틴과 채널에 대한 사전 이해를 제공할 것입니다. 도움이 되길 바랍니다!
Go 언어의 CSP
동시성 모델 구현에는 두 가지 주요 구성 요소가 포함되어 있습니다. 하나는 Goroutine
이고 다른 하나는 channel
입니다. . 이번 글에서는 기본적인 사용법과 주의사항을 소개하겠습니다. 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)
로그인 후 복사通过上述代码获得
channel
变量,我们可以对它执行发送与接收的操作。只接收的
channel
ch := make(<-chan int, 1)
로그인 후 복사通过上述代码获得
channel
变量,我们只能对它进行接收操作。只发送的
channel
ch := make(chan<- int, 1)
로그인 후 복사通过上述代码获得
channel
고루틴
고루틴
은Go
애플리케이션의 기본 실행 단위입니다. . 경량 사용자 수준 스레드이며 기본 레이어는코루틴
(코루틴)을 통해 구현된 동시성입니다. 우리 모두 알고 있듯이 코루틴은 사용자 모드에서 실행되는 사용자 스레드이므로Go
프로그램이 실행될 때Goroutine
도 예약됩니다. 🎜기본 사용법
🎜구문: go + 함수/메서드 🎜
🎜 go 키워드 + 함수/메서드고루틴
을 만들 수 있습니다. 🎜🎜코드 예: 🎜🎜실행 결과: 🎜func send(ch chan<- int) { ch <- 1 } func recv(ch <-chan int) { <-ch }
로그인 후 복사로그인 후 복사🎜func main() { ch := make(chan int, 5) ch <- 1 close(ch) ch <- 2 // panic: send on closed channel }
로그인 후 복사로그인 후 복사고루틴
이 여러 개 존재할 경우 실행 순서는 고정되지 않습니다. 따라서 인쇄할 때마다 결과가 달라집니다. 🎜🎜go
키워드를 통해 이름이 지정된 함수 / 메서드<를 기반으로고루틴
을 생성할 수 있음을 코드에서 볼 수 있습니다. /strong>, 익명 함수 / 클로저를 기반으로goroutine
을 생성할 수도 있습니다. 🎜🎜그럼고루틴
은 어떻게 종료되나요? 일반적인 상황에서는고루틴
함수의 실행이 종료되거나 실행이 반환되는 한 이는고루틴
의 종료를 의미합니다.고루틴
의 함수나 메소드에 반환값이 있는 경우고루틴
종료 시 해당 값은 무시됩니다. 🎜채널
🎜채널
은 Go 동시성 모델에서 중요한 역할을 합니다.고루틴
간의 통신을 구현하는 데 사용할 수 있으며,고루틴
간의 동기화를 구현하는 데에도 사용할 수 있습니다. 🎜채널 기본 동작
🎜채널
은 복합 데이터 유형이며channel
의 요소 유형을 선언할 때. 🎜🎜선언 구문: var ch chan string🎜
🎜위 코드를 통해 요소 유형이string
인채널
을 선언합니다. code >string 유형의 요소입니다.channel
은 참조 유형이며 데이터를 쓰기 전에 초기화해야 합니다.make
를 통해 초기화됩니다. 🎜🎜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 }
로그인 후 복사로그인 후 복사ch <- xxx
및x := <를 통해 <code>channel
변수ch
에 데이터를 보낼 수 있습니다. - ch는channel
변수ch
에서 데이터를 받을 수 있습니다. 🎜버퍼가 있는 채널과 버퍼가 없는 채널
🎜채널
을 초기화할 때 용량을 지정하지 않으면 무엇인가요? 생성된 버퍼링되지 않은채널
: 🎜rrreee🎜버퍼링되지 않은채널
의 전송 및 수신 작업은 전송 작업이 수행된 후 해당Goroutine
입니다. code>는 다른Goroutine
이 수신 작업을 수행할 수 있을 때까지 차단되며 그 반대의 경우도 마찬가지입니다. 전송 작업과 실행 작업이 동일한 고루틴에 배치되면 어떻게 되나요? 다음 코드를 살펴보세요. 🎜rrreee🎜프로그램이 실행된 후ch <-
에서치명적인 오류
가 발생하여 모든Goroutine<을 실행하라는 메시지가 표시됩니다. /code>는 Sleeping 상태, 즉 교착 상태입니다. 이러한 상황을 방지하려면 다른 <code>Goroutine
에서channel
의 전송 및 수신 작업을 실행해야 합니다. 🎜rrreee🎜위의 예에서 결론을 내릴 수 있습니다. 버퍼링되지 않은channel
의 전송 및 수신 작업은 두 개의 서로 다른Goroutine
에서 수행되어야 하며, 그렇지 않으면교착 상태
입니다. 코드> 이미지. 🎜
🎜용량을 지정하면 버퍼링된채널
이 생성됩니다. 🎜rrreee🎜버퍼링된채널
과 버퍼링되지 않은채널
은 다릅니다. 전송 작업을 수행할 때channel
의 버퍼가 가득 차 있지 않는 한Goroutine
은 버퍼가 가득 찰 때까지 중단되지 않습니다. >channel이 수행되는 경우에만 해당됩니다. 전송 작업으로 인해Goroutine
이 중단됩니다. 코드 예: 🎜rrreee채널의 전송 전용 유형 및 수신 전용 유형 선언
- 🎜Can 보내기와 받기 모두 수신된
channel
🎜rrreee🎜은 위 코드를 통해channel
변수를 얻고, 이에 대한 보내기 및 받기 작업을 수행할 수 있습니다. 🎜 - 🎜
channel
수신만🎜rrreee🎜channel
변수는 위 코드를 통해 얻어지며, 수신 작업만 수행할 수 있습니다. 🎜 - 🎜보내는
channel
🎜rrreee🎜만 위의 코드를 통해channel
변수를 얻어서 보낼 수만 있습니다. 🎜
通常只发送
channel
类型和只接收channel
类型,会被用作函数的参数类型或返回值:func send(ch chan<- int) { ch <- 1 } func recv(ch <-chan int) { <-ch }
로그인 후 복사로그인 후 복사channel 的关闭
通过内置函
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 }
로그인 후 복사로그인 후 복사管道
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 }
로그인 후 복사로그인 후 복사如果通过 for-range 遍历
channel
时,中途关闭channel
则会导致for-range
循环结束。
小结
本文首先介绍了
Goroutine
的创建方式以及其退出的时机是什么。其次介绍了如何创建
channel
类型变量的有缓冲与无缓冲的创建方式。需要注意的是,无缓冲的channel
发送与接收操作,需要在两个不同的Goroutine
中执行,否则会发送error
。接下来介绍如何定义只发送和只接收的
channel
类型。通常只发送channel
类型和只接收channel
类型,会被用作函数的参数类型或返回值。最后介绍了如何关闭
channel
,以及关闭之后的一些注意事项。위 내용은 Go 언어의 고루틴과 채널에 대한 예비 탐색의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!
- 🎜Can 보내기와 받기 모두 수신된

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











Go Language의 부동 소수점 번호 작동에 사용되는 라이브러리는 정확도를 보장하는 방법을 소개합니다.

Go Crawler Colly의 대기열 스레딩 문제는 Colly Crawler 라이브러리를 GO 언어로 사용하는 문제를 탐구합니다. � ...

GO 언어에서 구조를 정의하는 두 가지 방법 : VAR과 유형 키워드의 차이. 구조를 정의 할 때 Go Language는 종종 두 가지 다른 글쓰기 방법을 본다 : 첫째 ...

Go Language의 문자열 인쇄의 차이 : println 및 String () 함수 사용 효과의 차이가 진행 중입니다 ...

GO의 어떤 라이브러리가 대기업이나 잘 알려진 오픈 소스 프로젝트에서 개발 했습니까? GO에 프로그래밍 할 때 개발자는 종종 몇 가지 일반적인 요구를 만납니다.

골란드의 사용자 정의 구조 레이블이 표시되지 않으면 어떻게해야합니까? Go Language 개발을 위해 Goland를 사용할 때 많은 개발자가 사용자 정의 구조 태그를 만날 것입니다 ...

Go Language에서 메시지 대기열을 구현하기 위해 Redisstream을 사용하는 문제는 Go Language와 Redis를 사용하는 것입니다 ...

VSCODE 사용자의 GOLANG 제네릭 기능 유형 제약 조건을 자동으로 삭제하면 VSCODE를 사용하여 Golang 코드를 작성할 때 이상한 문제가 발생할 수 있습니다. 언제...
