You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
133 lines
1.7 KiB
Go
133 lines
1.7 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
func Aggregate[T any](cs ...<-chan T) <-chan T {
|
|
agg := make(chan T)
|
|
|
|
go func() {
|
|
defer close(agg)
|
|
for {
|
|
closed := 0
|
|
for _, c := range cs {
|
|
select {
|
|
case value, more := <-c:
|
|
if more {
|
|
agg <- value
|
|
} else {
|
|
closed++
|
|
}
|
|
default:
|
|
}
|
|
}
|
|
|
|
if closed == len(cs) {
|
|
break
|
|
}
|
|
}
|
|
}()
|
|
|
|
return agg
|
|
}
|
|
|
|
type TargetChan[T any] struct {
|
|
c <-chan T
|
|
target *T
|
|
}
|
|
|
|
type TryReceiver interface {
|
|
TryReceive() bool
|
|
}
|
|
|
|
func (tc TargetChan[T]) TryReceive() bool {
|
|
select {
|
|
case value := <-tc.c:
|
|
*tc.target = value
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func AwaitFirst(cancel context.CancelFunc, ws ...TryReceiver) {
|
|
done := make(chan struct{})
|
|
go func() {
|
|
defer close(done)
|
|
for {
|
|
for _, w := range ws {
|
|
if w.TryReceive() {
|
|
done <- struct{}{}
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
|
|
<-done
|
|
cancel()
|
|
return
|
|
}
|
|
|
|
func main() {
|
|
c1 := make(chan string)
|
|
c2 := make(chan int)
|
|
c3 := make(chan float64)
|
|
|
|
c := context.Background()
|
|
c, cancel := context.WithCancel(c)
|
|
|
|
go func() {
|
|
defer close(c1)
|
|
for {
|
|
select {
|
|
case <-c.Done():
|
|
return
|
|
case <-time.After(300 * time.Millisecond):
|
|
}
|
|
|
|
c1 <- "1"
|
|
}
|
|
}()
|
|
go func() {
|
|
defer close(c2)
|
|
for {
|
|
select {
|
|
case <-c.Done():
|
|
return
|
|
case <-time.After(400 * time.Millisecond):
|
|
}
|
|
|
|
c2 <- 2
|
|
}
|
|
}()
|
|
go func() {
|
|
defer close(c3)
|
|
for {
|
|
select {
|
|
case <-c.Done():
|
|
return
|
|
case <-time.After(200 * time.Millisecond):
|
|
}
|
|
|
|
c3 <- 3.0
|
|
}
|
|
}()
|
|
|
|
var result1 string
|
|
var result2 int
|
|
var result3 float64
|
|
|
|
AwaitFirst(
|
|
cancel,
|
|
TargetChan[string]{c1, &result1},
|
|
TargetChan[int]{c2, &result2},
|
|
TargetChan[float64]{c3, &result3},
|
|
)
|
|
|
|
fmt.Println(result1, result2, result3)
|
|
}
|