golang Context for goroutines

3547 단어
  • 개요
  • goroutine의 제어
  • 제어 해제
  • 제한 시간 제어
  • goroutine 사이의 전치
  • 요약
  • 개요


    Golang이 제공하는 채널 메커니즘은 CSP(Communication Sequencial Processes) 모델을 바탕으로 하는 병행 모델이다.
    채널을 통해 여러 개의 협업(goroutine) 간의 협업 코드를 쉽게 쓸 수 있고 순서의 코드를 병렬 코드로 바꾸는 것은 매우 간단하다.병렬 코드로 개조한 후에 다핵 하드웨어를 더욱 잘 활용하여 코드의 집행 효율을 효과적으로 높일 수 있으나 코드 제어의 문제를 가져왔다.
    병렬 코드는 순서대로 실행되는 코드보다 관리와 제어가 더 어려울 것이 분명하다. 이때golang이 제공하는 Context 인터페이스로 Goroutine을 제어하는 것을 도와야 한다.

    goroutine의 제어


    goroutine 사이의 가장 기본적인 제어는 바로 채널을 통해 데이터를 상호작용하는 것이다.
     1  func routineSample() {
     2    ch := make(chan int, 10)
     3    go p1(ch)
     4    go c1(ch)
     5    go c2(ch)
     6  
     7    time.Sleep(10 * time.Second)
     8  }
     9  
    10  func p1(ch chan int) {
    11    fmt.Println("Parent go routine!")
    12  
    13    for i := 0; i < 10; i++ {
    14      ch 

    상술한 것은 가장 기본적인 예이다. p1 함수는 채널에 끊임없이 데이터를 보내고 c1과 c2는 데이터를 처리한다.채널을 통해 c1, c2의 병발을 실현하는 것은 매우 간단하지만, p1이 c1을 제어하려면 c2가 그렇게 쉽지 않다는 것을 알 수 있다.
    이때, Context 인터페이스를 통해 병렬 프로토콜을 제어해야 한다.

    제어 해제


    제어를 취소하는 것은 임무의 발기자를 가리키며 특정한 조건하에서 신호를 보내서 이미 임무의 협정을 받아들여 임무의 집행을 중지하도록 지시한다.
     1  func routineSample() {
     2   ch := make(chan int, 10)
     3   ctx, cancel := context.WithCancel(context.Background())
     4   go p1(ctx, ch)
     5   go c1(ctx, ch)
     6   go c2(ctx, ch)
     7  
     8   // 300 ms      
     9   time.Sleep(300 * time.Millisecond)
    10   cancel()
    11  
    12   time.Sleep(10 * time.Second)
    13  }
    14  
    15  func p1(ctx context.Context, ch chan int) {
    16   fmt.Println("Parent go routine!")
    17  
    18   for i := 0; i < 10; i++ {
    19     ch 

    300밀리초 후 작업 취소 신호를 보내는 cancel(), c1과 c2는 select를 통해 취소 신호가 있는지 판단하고 취소 신호를 받은 후 처리를 종료합니다.
    실행 결과를 통해 알 수 있듯이 c1과 c2는 약 5~6개의 작업을 처리한 후 종료를 중지합니다.

    시간 제한 제어


    제어를 취소하는 것 외에 context에는 시간 초과 제어가 있습니다.
     1  func routineSample() {
     2   ch := make(chan int, 10)
     3   ctx, _ := context.WithTimeout(context.Background(), 300*time.Millisecond)
     4   go p1(ctx, ch)
     5   go c1(ctx, ch)
     6   go c2(ctx, ch)
     7  
     8   time.Sleep(10 * time.Second)
     9  }
    10  
    11  func p1(ctx context.Context, ch chan int) {
    12   fmt.Println("Parent go routine!")
    13  
    14   for i := 0; i < 10; i++ {
    15     ch 

    시간 초과를 제어하는 With Timeout도 cancel 함수를 되돌려줍니다. 시간 초과가 도착하기 전에 작업의 실행을 취소할 수 있습니다. 위의 예는 시간 초과를 기다린 후에 자동으로 작업을 취소합니다. cancel 함수를 사용하지 않았습니다.

    goroutine 사이의 전가


    일반적으로 Goroutine 간에 채널을 통해 전달하는 것은 모두 업무 데이터이다. 이외에 채널을 통해 Goroutine의 메타데이터를 제어할 수 있다.
     1  func routineSample() {
     2   ch := make(chan int, 10)
     3   //   goroutine  5   ,    ,         
     4   ctx := context.WithValue(context.Background(), "finish", 5)
     5   go p1(ctx, ch)
     6   go c1(ctx, ch)
     7   go c2(ctx, ch)
     8  
     9   time.Sleep(10 * time.Second)
    10  }
    11  
    12  func p1(ctx context.Context, ch chan int) {
    13   fmt.Println("Parent go routine!")
    14  
    15   for i := 0; i < 10; i++ {
    16     ch 

    위의 예는 context에 키 = "finish"의 작업 번호를 놓고 c1이나 c2가 받은 작업 번호가 같으면 작업 실행을 종료합니다.위의 예를 통해 알 수 있듯이 c1이나 c2가 5번 임무를 수행할 때 협업에서 탈퇴한다.그러나 5번 임무를 받은 사람은 확실하지 않다. 위의 코드를 몇 번 더 실행하면 때로는 c1이 종료되고, 때로는 c2가 종료되는 것을 발견할 수 있다.

    총결산


    context는 협정을 제어하고 발송하는 상하문이다. context를 이용하여 협정의 시간 초과를 대량으로 간소화하고 협정의 집행을 취소하며 협정 사이의 값을 전달하는 코드를 대량으로 간소화할 수 있다.context는 매우 편리하지만 함부로 사용할 수 없습니다. 채널을 통해 전달된 업무 데이터는 context에 넣지 마십시오.
    그 밖에 context는 라인이 안전하여 여러 개의 협정에서 안심하고 사용할 수 있다.

    좋은 웹페이지 즐겨찾기