목차
Goroutine
基本用法
channel
channel 的基本操作
带缓冲 channel 与无缓冲 channel
声明 channel 的只发送类型和只接收类型
고루틴
기본 사용법
채널
채널 기본 동작
버퍼가 있는 채널과 버퍼가 없는 채널
채널의 전송 전용 유형 및 수신 전용 유형 선언
channel 的关闭
小结
백엔드 개발 Golang Go 언어의 고루틴과 채널에 대한 예비 탐색

Go 언어의 고루틴과 채널에 대한 예비 탐색

Feb 02, 2023 pm 08:18 PM
golang 언어로 가다

이 글은 여러분에게 Go 언어의 고루틴과 채널에 대한 사전 이해를 제공할 것입니다. 도움이 되길 바랍니다!

Go 언어의 고루틴과 채널에 대한 예비 탐색

Go 언어의 CSP 동시성 모델 구현에는 두 가지 주요 구성 요소가 포함되어 있습니다. 하나는 Goroutine이고 다른 하나는 channel입니다. . 이번 글에서는 기본적인 사용법과 주의사항을 소개하겠습니다. CSP 并发模型的实现包含两个主要组成部分:一个是 Goroutine,另一个是 channel。本文将会介绍它们的基本用法和注意事项。

Goroutine

GoroutineGo 应用的基本执行单元,它是一种轻量的用户级线程,其底层是通过 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

通过上述代码声明一个元素类型为 stringchannel,其只能存放 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 <- xxxx := <를 통해 <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视频教程编程教学

      위 내용은 Go 언어의 고루틴과 채널에 대한 예비 탐색의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

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

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

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

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

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

GO에서 플로팅 포인트 번호 작업에 어떤 라이브러리가 사용됩니까? GO에서 플로팅 포인트 번호 작업에 어떤 라이브러리가 사용됩니까? Apr 02, 2025 pm 02:06 PM

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

Go 's Crawler Colly의 큐 스레드의 문제는 무엇입니까? Go 's Crawler Colly의 큐 스레드의 문제는 무엇입니까? Apr 02, 2025 pm 02:09 PM

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

GO 언어에서 'var'와 'type` 키워드 정의 구조의 차이점은 무엇입니까? GO 언어에서 'var'와 'type` 키워드 정의 구조의 차이점은 무엇입니까? Apr 02, 2025 pm 12:57 PM

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

이동 중에 왜 println 및 string () 함수로 문자열이 다른 효과를 갖는 이유는 무엇입니까? 이동 중에 왜 println 및 string () 함수로 문자열이 다른 효과를 갖는 이유는 무엇입니까? Apr 02, 2025 pm 02:03 PM

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

GO의 어떤 라이브러리가 대기업에서 개발하거나 잘 알려진 오픈 소스 프로젝트에서 제공합니까? GO의 어떤 라이브러리가 대기업에서 개발하거나 잘 알려진 오픈 소스 프로젝트에서 제공합니까? Apr 02, 2025 pm 04:12 PM

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

골란드의 사용자 정의 구조 레이블이 표시되지 않으면 어떻게해야합니까? 골란드의 사용자 정의 구조 레이블이 표시되지 않으면 어떻게해야합니까? Apr 02, 2025 pm 05:09 PM

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

Redis Stream을 사용하여 GO Language에서 메시지 대기열을 구현할 때 User_ID 유형 변환 문제를 해결하는 방법은 무엇입니까? Redis Stream을 사용하여 GO Language에서 메시지 대기열을 구현할 때 User_ID 유형 변환 문제를 해결하는 방법은 무엇입니까? Apr 02, 2025 pm 04:54 PM

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

VSCODE에서 자동으로 삭제되는 Golang 제네릭 기능 유형 제약 조건을 해결하는 방법은 무엇입니까? VSCODE에서 자동으로 삭제되는 Golang 제네릭 기능 유형 제약 조건을 해결하는 방법은 무엇입니까? Apr 02, 2025 pm 02:15 PM

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

See all articles