2017-10-24 5 views
4

다른 결과와 오류를 반환하는 두 가지 기능을 비동기 적으로 실행하는 방법을 찾고 있습니다. 두 가지 결과가 모두 완료 될 때까지 기다렸다가 인쇄 할 때까지 기다립니다. 또한 함수 중 하나가 오류를 반환하면 다른 함수를 기다리지 않고 오류를 인쇄하기 만하면됩니다. 예를 들어,이 기능을 가지고 :여러 goroutines의 결과 기다리기

여기
func methodInt(error bool) (int, error) { 
    <-time.NewTimer(time.Millisecond * 100).C 
    if error { 
     return 0, errors.New("Some error") 
    } else { 
     return 1, nil 
    } 
} 

func methodString(error bool) (string, error) { 
    <-time.NewTimer(time.Millisecond * 120).C 
    if error { 
     return "", errors.New("Some error") 
    } else { 
     return "Some result", nil 
    } 
} 

https://play.golang.org/p/-8StYapmlg 내가 그것을 구현하는 방법이지만, 내 생각은 너무 많은 코드가 있습니다. 인터페이스 {}를 사용하여 단순화 할 수 있지만이 방법을 사용하고 싶지는 않습니다. 예를 들어 async/await를 사용하여 C#으로 구현할 수있는 간단한 것을 원합니다. 아마도 이러한 작업을 단순화하는 라이브러리가있을 것입니다.

업데이트 : 감사합니다. 내가 얼마나 빨리 도움을 받았는지는 정말 멋지다! 나는 WaitGroup의 사용법을 좋아한다. 분명히 코드를 변경에보다 강력하게 만들었으므로 마지막에 정확한 메서드 수를 변경하지 않고도 다른 비동기 메서드를 쉽게 추가 할 수 있습니다. 그러나 C#에서와 비교할 때 여전히 많은 코드가 있습니다. 내가 알기로 명시 적으로 메소드를 비동기로 표시 할 필요가 없으므로 실제로 태스크를 리턴 할 수 있습니다. 그러나 메소드 호출은 훨씬 간단합니다. 예를 들어,이 링크를 고려하십시오. actually catching exception is also needed 그런데, 저는 이것을 태스크에서 발견했습니다 어쨌든 json에 마샬링 될 것이기 때문에 실제로 비동기로 실행하려는 함수의 반환 유형을 알 필요가 없습니다. 이제는 go-kit의 끝점 계층에서 여러 서비스를 호출합니다.

+4

는 IF [닫기 여러 goroutine의 사용 가능한 복제 오류가 발생합니다] (https://stackoverflow.com/questions/45500836/close-multiple-goroutine-if-an-error-occurs-in-one-in-go/45502591#45502591). – icza

답변

2

는 먼저 읽기 오류, 사용 사례에 대해이 샘플을해야 작품 :

package main 

import (
    "errors" 
    "sync" 
) 

func test(i int) (int, error) { 
    if i > 2 { 
     return 0, errors.New("test error") 
    } 
    return i + 5, nil 
} 

func test2(i int) (int, error) { 
    if i > 3 { 
     return 0, errors.New("test2 error") 
    } 
    return i + 7, nil 
} 

func main() { 
    results := make(chan int, 2) 
    errors := make(chan error, 2) 
    var wg sync.WaitGroup 
    wg.Add(1) 
    go func() { 
     defer wg.Done() 
     result, err := test(3) 
     if err != nil { 
      errors <- err 
      return 
     } 
     results <- result 
    }() 
    wg.Add(1) 
    go func() { 
     defer wg.Done() 
     result, err := test2(3) 
     if err != nil { 
      errors <- err 
      return 
     } 
     results <- result 
    }() 

    // here we wait in other goroutine to all jobs done and close the channels 
    go func() { 
     wg.Wait() 
     close(results) 
     close(errors) 
    }() 
    for err := range errors { 
     // here error happend u could exit your caller function 
     println(err.Error()) 
     return 

    } 
    for res := range results { 
     println("--------- ", res, " ------------") 
    } 
} 
0

난 당신이 이동 루틴은 비동기 적으로 실행하고 오류가 발생하면 완료 또는 프로그램을 종료 모두 대기 (설명은 아래 참조)가 할 수있는 방법의 더 작은, 독립적 인 예를 만들었습니다

package main 

import (
    "errors" 
    "fmt" 
    "math/rand" 
    "time" 
) 

func main() { 
    rand.Seed(time.Now().UnixNano()) 

    // buffer the channel so the async go routines can exit right after sending 
    // their error 
    status := make(chan error, 2) 

    go func(c chan<- error) { 
     if rand.Intn(2) == 0 { 
      c <- errors.New("func 1 error") 
     } else { 
      fmt.Println("func 1 done") 
      c <- nil 
     } 
    }(status) 

    go func(c chan<- error) { 
     if rand.Intn(2) == 0 { 
      c <- errors.New("func 2 error") 
     } else { 
      fmt.Println("func 2 done") 
      c <- nil 
     } 
    }(status) 

    for i := 0; i < 2; i++ { 
     if err := <-status; err != nil { 
      fmt.Println("error encountered:", err) 
      break 
     } 
    } 
} 

내가하는 일은 두 가지 루틴을 동기화하는 데 사용되는 채널을 만드는 것입니다. 그것에 쓰고 읽는 것은 차단합니다. 채널은 오류 값을 전달하는 데 사용되며 함수가 성공하면 nil을 전달합니다.

결국 채널에서 비동기 이동 루틴 당 하나의 값을 읽습니다. 이 값은 값이 수신 될 때까지 차단됩니다. 오류가 발생하면 루프를 종료하여 프로그램을 종료합니다.

함수는 무작위로 성공하거나 실패합니다.

루틴을 조정하는 방법에 대해 알려 드리겠습니다. 의견이 있으면 알려주세요.

참고 참고 :이 동작을 Go 놀이터에서 실행하면 rand.Seed는 아무 것도하지 않으며 놀이터는 항상 동일한 "임의"번호를 가지므로 동작이 변경되지 않습니다.

+0

채널을 닫거나 버퍼링합니다. 그렇지 않으면 goroutines (두 개의 전송이 있지만 첫 번째 값이 nil이 아닌 경우 하나의 receive 만 누락됩니다. 예를 들어 질문의 예와 같습니다). – Peter

+0

실제로 예제에서 프로그램은 런타임을 종료하는 기본 이동 루틴을 종료하므로 아무런 누출이 발생하지 않습니다. 그러나 당신이 옳다면, 더 복잡한 시나리오에서 이것이 문제가 될 수 있습니다. – gonutz

3

여기 sync.WaitGroup을 사용할 수 있습니다. 그것은 다른 goroutine의 동적 인 수를 기다릴 수 있습니다. 더 erorrs는 다음 결과를 읽을 경우는 오류 및 결과에 대한 두 개의 채널을 만들어야합니다

+1

https://nathanleclaire.com/blog/2014/02/15/how-to-wait-for-all-goroutines-to-finish-executing-before-continuing/ 멋진 블로그 게시물 sync.WaitGroup 및 문서 https : //golang.org/pkg/sync/#WaitGroup – jeffrey