>  기사  >  백엔드 개발  >  Golang 채널 Chan에 대한 자세한 설명

Golang 채널 Chan에 대한 자세한 설명

藏色散人
藏色散人앞으로
2020-11-09 15:40:542599검색

채널찬에 대해 고랭에 대해 소개하는 골랭 튜토리얼 칼럼이 필요한 친구들에게 도움이 되었으면 좋겠습니다!

Golang 채널 Chan에 대한 자세한 설명

먼저 golang에서 고루틴이라고도 불리는 스레드를 살펴봅니다

이 글을 읽기 전에 동시성과 병렬성을 이해해야 합니다. Golang의 스레드는 병렬성이 아닌 동시성 메커니즘입니다. 인터넷에서 차이점을 검색할 수 있습니다. 온라인에는 많은 소개가 있습니다.

먼저 예제를 살펴보겠습니다

import(
         "fmt"
)

funcmain(){

    go fmt.Println("1")
    fmt.Println("2")    
}

golang에서는 go 키워드 뒤에 함수를 사용하여 스레드를 생성할 수 있습니다. 후자의 함수는 미리 작성된 함수일 수도 있고 익명 함수일 수도 있습니다

funcmain(){    var i=3    go func(a int) {        fmt.Println(a)
        fmt.Println("1")
    }(i)
    fmt.Println("2")}

위 코드는 익명 함수를 생성하고 매개변수 i도 전달합니다. 아래 괄호 안의 i는 실제 매개변수입니다. 공식적인 매개변수.

그렇다면 위의 코드는 우리가 예상한 대로 1, 2, 3을 출력할 수 있을까요? 아니요. 프로그램은 2개만 인쇄할 수 있습니다. 아래에 올바른 코드를 게시하겠습니다

import(    "fmt"
    "time"    )funcmain(){    var i = 3    go func(a int) {        fmt.Println(a)
        fmt.Println("1")
    }(i)
    fmt.Println("2")
    time.Sleep(1 * time.Second)}

메인 스레드를 1초 동안 휴면 상태로 만드는 코드 한 줄을 마지막에 추가했을 뿐입니다. 그러면 프로그램이 2, 3, 1을 순서대로 인쇄합니다.

그렇다면 왜 이런 일이 일어나는 걸까요? 프로그램은 메인 스레드를 먼저 실행하기 때문에 메인 스레드의 실행이 완료된 후 프로그램은 즉시 종료되므로 하위 스레드를 실행할 추가 시간이 없습니다. 프로그램 종료 시 메인 스레드를 1초 동안 휴면 상태로 두면 프로그램은 하위 스레드를 실행할 수 있는 충분한 시간을 갖게 됩니다.


스레드는 여기서 마치고 채널을 살펴보겠습니다.

채널은 이름에서 알 수 있듯이 채널의 기능은 여러 스레드 간에 데이터를 전송하는 것입니다.

버퍼되지 않은 채널 만들기

chreadandwrite :=make(chan int)

chonlyread := make(<-chan int) //읽기 전용 채널 만들기

chonlywrite := make(chan<- int) // 읽기 전용 채널 만들기 쓰기 채널

예를 살펴보겠습니다:

    ch :=make(chan int)     
    ch <- 1
      go func() {
        <-ch
        fmt.Println("1")
      }()
      fmt.Println("2")

이 코드가 실행되면 오류가 발생합니다: 치명적인 오류: 모든 고루틴이 잠자기 상태입니다 - 교착 상태!

이 오류는 스레드가 떨어졌음을 의미합니다. 교착 상태에 빠지고 아래 프로그램을 계속 실행할 수 없습니다. 그렇다면 이 오류의 원인은 무엇입니까?

버퍼되지 않은 채널을 만든 다음 채널에 값을 할당한 후 할당이 완료된 후 프로그램이 교착 상태에 빠졌습니다. 채널이 버퍼링되지 않았으므로, 즉 동기식이므로 할당이 완료된 후 채널을 읽을 수 있기 전에 프로그램이 차단됩니다. 여기에 매우 중요한 개념이 있습니다. 채널 메커니즘은 선입선출 방식입니다. 채널에 값을 할당하면 해당 값을 읽어야 합니다. 그렇지 않으면 차단이 발생합니다. 물론 이는 버퍼링되지 않은 채널에만 유효합니다. . 버퍼링된 채널의 경우 송신자는 데이터가 버퍼에 복사될 때까지 차단합니다. 버퍼가 가득 차면 송신자는 수신자가 데이터를 제거한 후에만 차단 상태에서 복구할 수 있습니다.

위의 예에는 두 가지 해결 방법이 있습니다.

1. 채널에 버퍼를 추가한 다음 프로그램이 끝날 때 메인 스레드를 1초 동안 휴면 상태로 둡니다.

    ch :=make(chan int,1)
    ch <- 1
    go func() {
        v := <-ch
        fmt.Println(v)
    }()
    time.Sleep(1 * time.Second)
    fmt.Println("2")

여기서 이 경우 프로그램은 1, 2

2를 인쇄합니다. ch<-1 코드 줄을 하위 스레드 코드 뒤에 넣습니다. 코드는 다음과 같습니다.

    ch :=make(chan int)    go func() {
        v := <-ch
        fmt.Println(v)
    }()
    ch <- 1
    fmt.Println("2")

여기에서는 메인 스레드를 잠들게 할 필요가 없습니다. , 메인 스레드에 채널이 할당된 후 메인 스레드는 채널 값이 하위 스레드에서 검색될 때까지 차단되기 때문입니다.

마지막으로 생산자와 소비자의 예를 살펴보겠습니다.

import (    "fmt"
    "time")func produce(p chan<- int) {    for i := 0; i < 10; i++ {
        p <- i
        fmt.Println("send:", i)
    }
}func consumer(c <-chan int) {    for i := 0; i < 10; i++ {
        v := <-c
        fmt.Println("receive:", v)
    }
}func main() {
    ch := make(chan int)    go produce(ch)    go consumer(ch)
    time.Sleep(1 * time.Second)
}

이 코드에서는 채널이 버퍼링되지 않기 때문에 생산자가 채널에 값을 할당하면 생산자 스레드는 소비자 스레드가 걸릴 때까지 차단됩니다. 채널에서 데이터를 출력합니다. 소비자가 처음으로 데이터를 꺼낸 후 생산자가 아직 데이터를 저장하지 않았기 때문에 다음 주기 동안 소비자의 스레드도 차단됩니다. 이때 프로그램은 생산자의 스레드를 실행합니다. 이러한 방식으로 프로그램은 루프가 끝날 때까지 소비자 스레드와 생산자 스레드 사이를 계속 전환합니다.

버퍼링에 대한 또 다른 예를 살펴보겠습니다.

import (    "fmt"
    "time")func produce(p chan<- int) {    for i := 0; i < 10; i++ {
        p <- i
        fmt.Println("send:", i)
    }
}func consumer(c <-chan int) {    for i := 0; i < 10; i++ {
        v := <-c
        fmt.Println("receive:", v)
    }
}func main() {
    ch := make(chan int, 10)    go produce(ch)    go consumer(ch)
    time.Sleep(1 * time.Second)
}

이 프로그램에서 버퍼는 int 유형의 정수 10개를 저장할 수 있습니다. 생산자 스레드가 실행될 때 스레드는 차단되지 않고 한 번에 10개의 정수가 저장됩니다. 정수는 채널에 저장되며 읽을 때 한꺼번에 읽혀집니다.

위 내용은 Golang 채널 Chan에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 csdn.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제