Golang의 동시성 소개

4284 단어 go
golang series,의 이 단원에서는 Golang의 동시성에 대해 알아봅니다.

동시성은 많은 계산을 동시에 실행하는 것을 의미합니다. 우리가 좋든 싫든 동시성은 네트워크에 연결된 여러 컴퓨터와 같은 모든 측면에서 현대 프로그래밍에 스며듭니다. 하나의 컴퓨터에서 많은 앱이 실행되고 있습니다. 많은 프로세서가 있는 컴퓨터(오늘날 단일 칩에 여러 개의 프로세서 코어가 있는 경우가 많음)

동시성 대 병렬성



많은 작업이 동시에 실행될 수 있는 경우 이를 동시성이라고 합니다. CPU는 비교적 빠르게 작업을 전환하기 때문에 병렬로 작동하는 수많은 프로세스의 모습은 착각입니다. 단일 코어 CPU는 동시에 실행되는 두 프로세스를 처리할 수 없습니다. 실제로 많은 CPU가 동시에 사용되는 경우를 병렬 처리라고 합니다. Read more

Golang의 동시성



Golang의 동시성은 내장된 고루틴 기능을 통해 구현됩니다. Go 전용 고루틴은 다른 코드 또는 애플리케이션과 동시에 실행되는 기능입니다. 경량 스레드로 간주될 수 있지만 OS 스레드는 아닙니다. Go의 런타임은 고루틴과 밀접하게 엮여 있습니다.

Golang에서 동시성을 위한 Go 루틴



Go 루틴은 다른 함수와 나란히 또는 동시에 실행할 수 있는 함수 유형입니다. Go 루틴은 만들기가 상당히 쉽습니다. Go 키워드를 접두사로 붙여서 함수 실행을 쉽게 병렬화할 수 있습니다. 매우 가볍기 때문에 수만 개의 Go 루틴을 생성할 수 있습니다. 간단한 예를 살펴보겠습니다.

package main
import (
  "fmt"
  "time"
)
func main() {
  go c()
  fmt.Println("I am main")
  time.Sleep(time.Second * 2)
}
func c() {
  time.Sleep(time.Second * 2)
  fmt.Println("I am concurrent")
}
//=> I am main
//=> I am concurrent


함수 c는 위의 예에서 볼 수 있듯이 기본 Go 스레드와 동시에 실행되는 Go 프로시저입니다. 여러 스레드에 리소스를 분배하려는 경우가 있습니다. Go는 스레드 간에 변수를 공유하지 않는 것을 선호합니다. 그렇게 하면 교착 상태 및 리소스 대기 가능성이 높아지기 때문입니다. Go 채널은 Go 루틴 간에 리소스를 공유하는 다른 방법입니다.

채널



채널을 사용하여 두 Go 프로시저 간에 데이터를 전송할 수 있습니다. 채널을 구성할 때 채널이 수신할 데이터 종류를 선언하는 것이 중요합니다. 아래와 같이 간단한 문자열 유형 채널을 만들어 보겠습니다.

c := make(chan string)


이 채널을 통해 문자열 유형의 데이터를 전송할 수 있습니다. 이 채널에서 데이터는 두 가지 방법으로 전송될 수 있습니다.

package main

import "fmt"

func main(){
  c := make(chan string)
  go func(){ c <- "hello" }()
  msg := <-c
  fmt.Println(msg)
}
//=>"hello"


수신 채널은 발신자로부터 데이터를 받을 때까지 데이터 전송을 보류합니다.

단방향 채널



어떤 상황에서는 Go 함수가 채널을 통해 데이터를 전송하지만 대신 수신하기를 원합니다. 이를 위해 단방향 채널을 설계할 수도 있습니다. 간단한 예를 살펴보겠습니다.

package main

import (
 "fmt"
)

func main() {
 ch := make(chan string)

 go sc(ch)
 fmt.Println(<-ch)
}

func sc(ch chan<- string) {
 ch <- "hello"
}


sc라는 이름의 Go 프로시저는 위의 예에서 채널로만 메시지를 보낼 수 있습니다. 메시지를 받을 수 없습니다.

선택을 사용하여 Go 루틴을 위한 여러 채널 구성



기능이 한 번에 여러 채널에서 대기 중일 수 있습니다. 이를 위해 선택 진술을 사용할 수 있습니다. 더 명확하게 하기 위해 다음 예를 살펴보겠습니다.

package main

import (
 "fmt"
 "time"
)

func main() {
 c1 := make(chan string)
 c2 := make(chan string)
 go speed1(c1)
 go speed2(c2)
 fmt.Println("The first to arrive is:")
 select {
 case s1 := <-c1:
  fmt.Println(s1)
 case s2 := <-c2:
  fmt.Println(s2)
 }
}

func speed1(ch chan string) {
 time.Sleep(2 * time.Second)
 ch <- "speed 1"
}

func speed2(ch chan string) {
 time.Sleep(1 * time.Second)
 ch <- "speed 2"
}


메인은 위의 예에서 c1과 c2의 두 채널을 기다리고 있습니다. main 함수는 선택한 case 문을 사용하여 먼저 받는 메시지에 따라 채널에서 메시지를 출력합니다.

버퍼링된 채널



Go에서는 버퍼링된 채널을 만들 수 있습니다. 버퍼를 사용하여 채널로 보낸 메시지는 버퍼가 가득 차면 중지됩니다. 그림을 살펴보겠습니다.

package main

import "fmt"

func main(){
  ch := make(chan string, 2)
  ch <- "hello"
  ch <- "world"
  ch <- "!" # extra message in buffer
  fmt.Println(<-ch)
}

# => fatal error: all goroutines are asleep - deadlock!


위에서 볼 수 있듯이 하나의 채널에서 두 개 이상의 메시지를 수락할 수 없습니다.

더 알아보기

Learn Error Handling in Golang

Learn Packages in Golang

좋은 웹페이지 즐겨찾기