>  기사  >  백엔드 개발  >  Go 언어의 동시성 모드와 병렬 컴퓨팅을 마스터하세요.

Go 언어의 동시성 모드와 병렬 컴퓨팅을 마스터하세요.

王林
王林원래의
2023-11-30 09:30:33765검색

Go 언어의 동시성 모드와 병렬 컴퓨팅을 마스터하세요.

인터넷의 급속한 발전과 함께 대규모 분산 시스템에 대한 수요가 점점 더 높아지고 있으며, 동시 프로그래밍과 병렬 컴퓨팅은 인터넷 개발자가 반드시 마스터해야 하는 기술이 되었습니다. Go 언어는 동시성 프로그래밍과 병렬 컴퓨팅을 지원하기 위해 탄생한 언어입니다. 이 글에서는 Go 언어의 동시성 모드와 병렬 컴퓨팅을 소개하고, 독자들의 심도 있는 이해를 돕기 위해 몇 가지 실제 사례를 제시합니다.

1. Go 언어의 동시성 모드

Go 언어의 동시성 모드는 주로 고루틴과 채널의 두 가지 기본 구성 요소를 기반으로 합니다. 고루틴은 Go 언어의 런타임 시스템에 의해 관리되는 경량 스레드입니다. go 키워드를 통해 시작할 수 있으며, 고루틴은 채널을 통해 통신할 수 있습니다.

다음은 고루틴과 채널의 간단한 예입니다.

package main

import "fmt"

func printMsg(msg string, ch chan string) {
    ch <- msg
}

func main() {
    ch := make(chan string)
    msgs := []string{"Hello", "Golang", "Parallel"}

    for _, msg := range msgs {
        go printMsg(msg, ch)
    }

    for i := 0; i < len(msgs); i++ {
        fmt.Println(<-ch)
    }
}

코드는 for 루프를 통해 세 개의 고루틴을 시작하고 각각 세 개의 문자열을 출력합니다. printMsg 함수는 문자열 메시지를 채널에 쓰고, 주 함수는 채널에서 다시 읽습니다.

1.1 파이프라인 모드

Go 언어에서는 파이프라인 모드를 통해 여러 고루틴을 직렬로 연결하여 보다 복잡한 동시 시스템을 형성할 수 있습니다. 파이프라인 패턴의 구현은 일반적으로 여러 고루틴 간의 채널 통신, 한 고루틴에서 다른 고루틴으로 데이터 전달, 각 고루틴의 데이터 처리 및 변환을 통해 이루어집니다. 다음은 간단한 파이프라인 모드 예입니다.

package main

import (
    "fmt"
)

func addOne(in <-chan int, out chan<- int) {
    for val := range in {
        out <- val + 1
    }
    close(out)
} 

func printNums(out <-chan int) {
    for val := range out {
        fmt.Println(val)
    }
}

func main() {    
    nums := []int{1, 2, 3}
    in := make(chan int)
    out := make(chan int)

    go addOne(in, out)

    go printNums(out)

    for _, num := range nums {
        in <- num
    }
    close(in)
}

코드는 3개의 고루틴, 즉 입력 고루틴과 1개의 처리 고루틴 및 출력 고루틴을 정의합니다. addOne 함수는 입력 채널의 데이터에 1을 더하고 이를 출력 채널에 씁니다. printNums 이 함수는 출력 채널에서 데이터를 읽고 출력합니다.

1.2 선택 패턴

Go 언어의 select 문은 다중 채널, 즉 선택 패턴(select 패턴)을 처리할 수 있는 편리한 방법을 제공합니다. 선택 모드를 사용하면 여러 채널에서 비차단 선택 작업을 수행할 수 있습니다. 여러 채널에 읽거나 쓸 수 있는 메시지가 있으면 작업을 위해 자동으로 선택됩니다.

다음은 간단한 선택 모드의 예입니다.

package main

import "fmt"

func ping(ch chan<- string) {
    for {
        ch <- "ping"
    }
}

func pong(ch chan<- string) {
    for {
        ch <- "pong"
    }
}

func printer(ch <-chan string) {
    for {
        fmt.Println(<-ch)
    }
}

func main() {
    ch1 := make(chan string)
    ch2 := make(chan string)
    ch3 := make(chan string)

    go ping(ch1)
    go pong(ch2)
    go printer(ch3)

    for {
        select {
        case msg := <-ch1:
            ch3 <- msg
        case msg := <-ch2:
            ch3 <- msg
        }
    }
}

코드에서 ping 함수와 pong 함수는 각각 ch1과 ch2에 "ping"과 "pong" 메시지를 보내고, 프린터 함수는 ch3의 메시지를 읽고 출력합니다. 그것. 기본 기능에서는 select 문을 사용하여 ch1 및 ch2의 메시지를 모니터링하고 수신된 메시지를 ch3을 통해 프린터 기능에 전달하여 출력합니다.

2. Go 언어의 병렬 컴퓨팅

Go 언어의 내장 병렬 컴퓨팅 모듈에는 동기화, 원자 및 컨텍스트 등이 포함됩니다. sync와 Atomic은 동시 데이터 접근을 제어하기 위해 주로 mutex(Mutex)와 Atomic 연산(atomic 연산)을 사용하고, Context는 고루틴의 컨텍스트 정보를 관리하는 데 사용됩니다. 다음은 이러한 모듈을 사용하는 방법에 대한 간략한 소개입니다.

2.1 뮤텍스 잠금

뮤텍스 잠금은 공유 리소스를 보호하기 위해 가장 일반적으로 사용되는 동기화 메커니즘 중 하나이며 Go 언어의 가장 기본적인 동기화 메커니즘 중 하나이기도 합니다. . Go 언어에서는 동기화 패키지의 Mutex 유형을 통해 뮤텍스 잠금을 생성할 수 있습니다. Mutex 유형은 Lock 및 Unlock이라는 두 가지 중요한 방법을 제공합니다. 공유 리소스에 액세스하기 전에 Lock 메서드를 호출하여 잠금을 획득한 다음, 액세스가 완료된 후 Unlock 메서드를 호출하여 잠금을 해제해야 합니다. 다음은 간단한 뮤텍스 잠금 예입니다.

package main

import (
    "fmt"
    "sync"
)

func addOne(num *int, mutex *sync.Mutex, wg *sync.WaitGroup) {
    mutex.Lock()
    *num += 1
    mutex.Unlock()

    wg.Done()
}

func main() {
    var wg sync.WaitGroup
    var num int

    mutex := &sync.Mutex{}
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go addOne(&num, mutex, &wg)
    }

    wg.Wait()
    fmt.Println(num)
}

코드에서 addOne 함수는 num 변수에 1을 추가하도록 정의되어 있습니다. 1을 추가하기 전에 뮤텍스 잠금을 획득해야 하며 추가 후에는 뮤텍스 잠금을 해제해야 합니다. 1. WaitGroup을 사용하여 모든 고루틴이 실행을 완료하고 최종 결과를 출력할 때까지 기다립니다.

2.2 원자 연산

높은 동시성 시나리오에서 뮤텍스 잠금은 프로그램 성능을 저하시킬 수 있으므로 Go 언어는 뮤텍스 잠금을 대체하기 위한 원자 연산을 제공합니다. 원자 패키지는 AddInt64, CompareAndSwapInt64, SwapInt64 등과 같은 여러 원자 작업 기능을 제공합니다. 원자적 연산을 사용하면 변수에 대한 연산이 다른 고루틴에 의해 중단되지 않으며 동시 실행이 영향을 받지 않습니다. 다음은 간단한 원자 연산 예입니다.

package main

import (
    "fmt"
    "sync/atomic"
)

func addOne(num *int64, count *int64, done chan bool) {
    for i := 0; i < 1000; i++ {
        atomic.AddInt64(num, 1)
    }
    atomic.AddInt64(count, 1)
    done <- true
}

func main() {
    var num int64
    var count int64
    done := make(chan bool)

    for i := 0; i < 100; i++ {
        go addOne(&num, &count, done)
    }

    for i := 0; i < 100; i++ {
        <-done
    }

    fmt.Printf("num=%d, count=%d
", num, count)
}

코드에서는 원자 패키지의 AddInt64 함수를 사용하여 num 변수에 대한 원자 연산을 수행하고, 작업이 완료된 후 메인 스레드에 done을 통해 알립니다. count 변수는 일반적인 AddInt64 함수를 통해 누적되고, 최종적으로 num과 count의 값이 출력된다.

2.3 컨텍스트 관리

Go 언어에서는 요청 ID, 시간 제한 설정 등과 같은 여러 고루틴 간에 컨텍스트 정보를 전달해야 하는 경우가 많습니다. 컨텍스트 패키지는 고루틴 컨텍스트 정보를 관리하는 편리한 방법을 제공합니다. 컨텍스트를 사용할 때 일반적으로 기본 고루틴에서 상위 컨텍스트를 생성해야 합니다. 고루틴을 파생할 때 WithCancel, WithDeadline, WithValue 및 기타 함수를 사용하여 하위 컨텍스트를 생성하고 해당 컨텍스트 정보를 전달합니다. 다음은 간단한 컨텍스트 관리 예시입니다.

package main

import (
    "context"
    "fmt"
    "time"
)

func worker(ctx context.Context, id int) {
    for {
        select {
        case <-ctx.Done():
            fmt.Printf("worker %d canceled
", id)
            return
        default:
            fmt.Printf("worker %d is working
", id)
            time.Sleep(1 * time.Second)
        }
    }
}

func main() {
    ctx, cancel := context.WithCancel(context.Background())

    for i := 0; i < 3; i++ {
        go worker(ctx, i)
    }

    time.Sleep(5 * time.Second)

    cancel()
}

코드에서 context 패키지를 사용해 상위 컨텍스트를 생성하고, WithCancel 함수를 통해 하위 컨텍스트를 생성합니다. 작업자 함수에서 select 문을 사용하여 ctx.Done()의 신호를 수신합니다. ctx.Done()이 닫히면 컨텍스트가 취소되고 작업자 함수가 종료되어야 함을 의미합니다. 메인 함수에서 취소 함수를 통해 하위 컨텍스트를 닫고 하위 컨텍스트가 취소될 때까지 기다립니다. 실행 결과는 다음과 같습니다.

worker 0 is working
worker 1 is working
worker 2 is working
worker 2 canceled
worker 1 canceled
worker 0 canceled

상위 컨텍스트가 취소되면 모든 하위 컨텍스트가 알림을 받고 실행을 종료합니다.

3.결론

이 글에서는 Go 언어의 동시성 모드와 병렬 컴퓨팅을 간략하게 소개하고, 고루틴, 채널, 뮤텍스 잠금, 원자 연산, 컨텍스트 등 기본 구성 요소와 모듈을 소개합니다. 이러한 기본 지식을 학습함으로써 우리는 Go 언어의 동시성 및 병렬 프로그래밍을 더 잘 익힐 수 있으며 고성능, 높은 동시성 인터넷 애플리케이션을 구축하기 위한 기반을 마련할 수 있습니다.

위 내용은 Go 언어의 동시성 모드와 병렬 컴퓨팅을 마스터하세요.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

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