假设我有一个函数IsAPrimaryColour(),它通过调用其他三个函数IsRed()、IsGreen()和IsBlue() 来工作。由于这三个功能彼此完全独立,因此它们可以同时运行。退货条件为:
- 如果三个函数中的任何一个返回 true,IsAPrimaryColour() 也应该返回 true。无需等待其他功能完成。即:IsPrimaryColour()如果IsRed()为真或IsGreen()为真或IsBlue()为真,则为真
- 如果所有函数都返回 false,IsAPrimaryColour() 也应该返回 false。即:如果IsRed()为假且IsGreen ()为假且IsBlue ( )为假,则IsPrimaryColour()为假
- 如果三个函数中的任何一个返回错误,IsAPrimaryColour() 也应该返回错误。无需等待其他功能完成或收集任何其他错误。
我正在努力解决的问题是,如果任何其他三个函数返回 true,如何退出该函数,但如果它们都返回 false,则还要等待所有三个函数都完成。如果我使用 sync.WaitGroup 对象,我需要等待所有 3 个 go 例程完成,然后才能从调用函数返回。
因此,我使用循环计数器来跟踪我在频道上收到消息的次数以及在收到所有 3 条消息后存在的程序。
https://play.golang.org/p/kNfqWVq4Wix
package main
import (
"errors"
"fmt"
"time"
)
func main() {
x := "something"
result, err := IsAPrimaryColour(x)
if err != nil {
fmt.Printf("Error: %v\n", err)
} else {
fmt.Printf("Result: %v\n", result)
}
}
func IsAPrimaryColour(value interface{}) (bool, error) {
found := make(chan bool, 3)
errors := make(chan error, 3)
defer close(found)
defer close(errors)
var nsec int64 = time.Now().UnixNano()
//call the first function, return the result on the 'found' channel and any errors on the 'errors' channel
go func() {
result, err := IsRed(value)
if err != nil {
errors <- err
} else {
found <- result
}
fmt.Printf("IsRed done in %f nanoseconds \n", float64(time.Now().UnixNano()-nsec))
}()
//call the second function, return the result on the 'found' channel and any errors on the 'errors' channel
go func() {
result, err := IsGreen(value)
if err != nil {
errors <- err
} else {
found <- result
}
fmt.Printf("IsGreen done in %f nanoseconds \n", float64(time.Now().UnixNano()-nsec))
}()
//call the third function, return the result on the 'found' channel and any errors on the 'errors' channel
go func() {
result, err := IsBlue(value)
if err != nil {
errors <- err
} else {
found <- result
}
fmt.Printf("IsBlue done in %f nanoseconds \n", float64(time.Now().UnixNano()-nsec))
}()
//loop counter which will be incremented every time we read a value from the 'found' channel
var counter int
for {
select {
case result := <-found:
counter++
fmt.Printf("received a value on the results channel after %f nanoseconds. Value of counter is %d\n", float64(time.Now().UnixNano()-nsec), counter)
if result {
fmt.Printf("some goroutine returned true\n")
return true, nil
}
case err := <-errors:
if err != nil {
fmt.Printf("some goroutine returned an error\n")
return false, err
}
default:
}
//check if we have received all 3 messages on the 'found' channel. If so, all 3 functions must have returned false and we can thus return false also
if counter == 3 {
fmt.Printf("all goroutines have finished and none of them returned true\n")
return false, nil
}
}
}
func IsRed(value interface{}) (bool, error) {
return false, nil
}
func IsGreen(value interface{}) (bool, error) {
time.Sleep(time.Millisecond * 100) //change this to a value greater than 200 to make this function take longer than IsBlue()
return true, nil
}
func IsBlue(value interface{}) (bool, error) {
time.Sleep(time.Millisecond * 200)
return false, errors.New("something went wrong")
}
虽然这工作得很好,但我想知道我是否没有忽略一些语言功能以更好地做到这一点?