> 일반적인 문제 > Go 언어로 동시성 제어를 구현하는 방법

Go 언어로 동시성 제어를 구현하는 방법

DDD
풀어 주다: 2023-06-08 14:42:57
원래의
1871명이 탐색했습니다.

Go 언어에서 동시성 제어를 구현하는 방법: 1. 여러 고루틴의 작업 처리에는 종속성 또는 연결 관계가 있습니다. 2. 채널에서는 여러 그루틴의 데이터 전송을 적극적으로 취소할 수 있습니다. Context의 기능을 충족합니다. 3. 컨텍스트, 메타데이터 전파, 신호 전파 취소, 시간 초과 제어 등을 포함한 다중 레벨 그루틴 간의 신호 전파.

Go 언어로 동시성 제어를 구현하는 방법

이 기사의 운영 환경: Windows 10 시스템, go1.20 버전, dell g3 컴퓨터.

Golang에서는 go 키워드를 통해 고루틴을 열 수 있으므로 Go에서 동시 코드를 쉽게 작성할 수 있습니다. 그러나 동시에 실행되는 그루틴을 효과적으로 제어하는 ​​방법은 무엇입니까?

동시성 제어에 관해 많은 사람들이 먼저 잠금을 생각할 수 있습니다. Golang은 또한 mutex lock sync.Mutex 및 읽기-쓰기 잠금 sync.RWMutex를 포함한 잠금 관련 메커니즘을 제공합니다. 잠금 외에도 원자적 작업인 동기화/원자성 등도 있습니다. 그러나 이러한 메커니즘의 초점은 고루틴의 동시 데이터 안전성입니다. 이 기사에서 논의하고 싶은 것은 고루틴의 동시성 동작 제어입니다.

고루틴 동시 동작 제어에는 WaitGroup, 채널 및 컨텍스트라는 세 가지 일반적인 방법이 있습니다.

WaitGroup

WaitGroup은 sync 패키지 하위에 있으며, 사용법은 다음과 같습니다.

func main() {
  var wg sync.WaitGroup

  wg.Add(2) //添加需要完成的工作量2

  go func() {
    wg.Done() //完成工作量1
    fmt.Println("goroutine 1 完成工作!")
  }()

  go func() {
    wg.Done() //完成工作量1
    fmt.Println("goroutine 2 完成工作!")
  }()

  wg.Wait() //等待工作量2均完成
  fmt.Println("所有的goroutine均已完成工作!")}输出:
//goroutine 2 完成工作!
//goroutine 1 完成工作!
//所有的goroutine均已完成工作!
로그인 후 복사

WaitGroup 이 동시성 제어 방법은 특정 작업에 여러 고루틴이 함께 작동해야 하는 상황에 특히 적합하며, 각 고루틴은 작업의 일부만 수행할 수 있으며 모든 고루틴이 완료될 때만 작업이 완료됩니다. 그러므로 WaitGroup은 기다림의 방식이라는 이름과 같은 의미를 갖고 있습니다.

그러나 실제 비즈니스에는 시나리오가 있습니다. 특정 요구 사항이 충족되면 특정 고루틴이 종료되도록 적극적으로 알려야 합니다. 예를 들어, 백그라운드 모니터링 고루틴을 시작하면 모니터링이 더 이상 필요하지 않을 때 모니터링 고루틴에 종료를 알려야 합니다. 그렇지 않으면 계속 유휴 상태가 되어 누출이 발생하게 됩니다.

Channel

위의 시나리오에서 WaitGroup은 무력합니다. 생각할 수 있는 가장 간단한 방법은 전역 변수를 정의하고 이 변수를 다른 곳에서 수정하여 이를 알리는 것입니다. 백그라운드 고루틴은 이 변수가 변경된 것을 발견하면 자체적으로 닫힙니다. 다소 번거롭습니다. 이 경우 채널+선택이 유용할 수 있습니다.

func main() {
  exit := make(chan bool)

  go func() {
    for {
      select {
      case <-exit:
        fmt.Println("退出监控")
        return
      default:
        fmt.Println("监控中")
        time.Sleep(2 * time.Second)
      }
    }
  }()

  time.Sleep(5 * time.Second)
  fmt.Println("通知监控退出")
  exit <- true

  //防止main goroutine过早退出
  time.Sleep(5 * time.Second)}输出:
//监控中
//监控中
//监控中
//通知监控退出
//退出监控
로그인 후 복사

이 채널+선택 조합은 고루틴 종료를 알리는 더 우아한 방법입니다.

그러나 이 솔루션에도 한계가 있습니다. 상상해 보세요. 종료하기 위해 모두 제어해야 하는 고루틴이 여러 개 있다면 어떻게 될까요? 이 고루틴이 다른 고루틴을 생성하면 어떻게 될까요? 물론 이 문제를 해결하기 위해 많은 채널을 정의할 수 있지만 고루틴의 관계 체인은 이 시나리오를 복잡하게 만듭니다.

Context

위의 시나리오는 CS 아키텍처 모델에서 일반적입니다. Go에서는 일련의 요청을 처리하기 위해 각 클라이언트에 대해 별도의 고루틴(A)이 열리는 경우가 많으며, 종종 단일 A가 다른 서비스도 요청하고(다른 고루틴 B 시작) B도 다른 고루틴 C, C를 요청할 수 있습니다. 예를 들어 Databse 서버로 요청을 보냅니다. 클라이언트의 연결이 끊어지면 시스템이 A, B, C가 차지한 리소스를 회수하기 전에 클라이언트와 연결된 A, B, C가 즉시 종료되어야 한다고 상상해 보세요. A를 종료하는 것은 간단하지만 B와 C도 종료하도록 알리는 방법은 무엇입니까?

이때 Context가 나타납니다.

func A(ctx context.Context, name string)  {
  go B(ctx ,name) //A调用了B  for {
    select {
    case <-ctx.Done():
      fmt.Println(name, "A退出")
      return
    default:
      fmt.Println(name, "A do something")
      time.Sleep(2 * time.Second)
    }
  }}func B(ctx context.Context, name string)  {
  for {
    select {
    case <-ctx.Done():
      fmt.Println(name, "B退出")
      return
    default:
      fmt.Println(name, "B do something")
      time.Sleep(2 * time.Second)
    }
  }}func main() {
  ctx, cancel := context.WithCancel(context.Background())

  go A(ctx, "【请求1】") //模拟client来了1个连接请求

  time.Sleep(3 * time.Second)
  fmt.Println("client断开连接,通知对应处理client请求的A,B退出")
  cancel() //假设满足某条件client断开了连接,那么就传播取消信号,ctx.Done()中得到取消信号

  time.Sleep(3 * time.Second)}输出:
//【请求1】 A do something
//【请求1】 B do something
//【请求1】 A do something
//【请求1】 B do something
//client断开连接,通知对应处理client请求的A,B退出
//【请求1】 B退出
//【请求1】 A退出
로그인 후 복사

예제에서는 클라이언트에서 연결 요청이 시뮬레이션되고 이에 따라 Goroutine A가 열리고 A와 B 모두 취소 기능을 사용하여 추적할 수 있습니다. , 이 두 개의 모든 고루틴이 종료됩니다.

이것은 컨트롤러와 같습니다. 스위치를 누르면 이 컨텍스트를 기반으로 하거나 파생된 모든 하위 컨텍스트가 이때 정리 작업을 수행할 수 있으며 고루틴이 수행됩니다. 드디어 출시되었습니다. 이것은 시작 후 제어할 수 없는 고루틴 문제를 우아하게 해결합니다.

Context의 자세한 사용법은 이 문서의 범위를 벗어납니다. Context 패키지를 구체적으로 설명하는 후속 기사가 있을 예정이므로 계속 지켜봐 주시기 바랍니다.

요약

이 문서에는 Golang의 세 가지 동시성 동작 제어 모드가 나열되어 있습니다. 모드 간에는 좋고 나쁨의 차이가 없으며 단지 다양한 시나리오에 적합한 솔루션을 사용하는 것에 달려 있습니다. 실제 프로젝트에서는 여러 가지 방법을 조합하여 사용하는 경우가 많습니다.

  • WaitGroup: 여러 고루틴의 작업 처리에는 종속성 또는 접합 관계가 있습니다.
  • channel+select: 여러 그루틴에서 고루틴을 적극적으로 취소할 수 있습니다. 채널은 WaitGroup의 작업을 대체할 수 있지만 여러 채널이 컨텍스트의 기능을 충족할 수 있을 뿐만 아니라 코드도 만들 수 있습니다. 논리가 복잡하다.
  • 컨텍스트: 다중 레벨 그루틴 간의 신호 전파(메타데이터 전파, 신호 전파 취소, 시간 초과 제어 등 포함).

Golang에서는 go 키워드를 통해 고루틴을 열 수 있으므로 Go에서 동시 코드를 쉽게 작성할 수 있습니다. 그러나 동시에 실행되는 그루틴을 효과적으로 제어하는 ​​방법은 무엇입니까?

동시성 제어에 관해 많은 사람들이 먼저 잠금을 생각할 수 있습니다. Golang은 또한 mutex lock sync.Mutex 및 읽기-쓰기 잠금 sync.RWMutex를 포함한 잠금 관련 메커니즘을 제공합니다. 잠금 외에도 원자적 작업인 동기화/원자성 등도 있습니다. 그러나 이러한 메커니즘의 초점은 고루틴의 동시 데이터 안전성입니다. 이 기사에서 논의하고 싶은 것은 고루틴의 동시성 동작 제어입니다.

고루틴 동시 동작 제어에는 WaitGroup, 채널 및 컨텍스트라는 세 가지 일반적인 방법이 있습니다.

위 내용은 Go 언어로 동시성 제어를 구현하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿