2010-11-18 22 views
8

Go, select bildiriminin birkaç kanalından birinde engelleme okuması yapmak için bir mekanizmaya sahiptir. Bu nedenle, bu iki kanaldan birinden giriş yapana kadarGo'daki kanalların dinamik listesinde giriş nasıl seçilir?

'u engelleyebilirsiniz. Çok hoş.

Ancak bu, kaynak kodda kaç tane kanalın yoklamak istediğimi belirtmemizi gerektirir. Bir dilim veya bir dizi kanalım varsa ve bunlardan herhangi birini girene kadar engellemek istersem ne olur?

cevap

4

Sadece bir düşünün, ancak her ikisini de engelleyen 2 kanalı olan bir goroutini ürettiğiniz ve çıkışı yeni bir kanala gönderdiği bir çoğullama modeli kullanabilirsiniz. Ardından, listenizden dinamik olarak her şeyi tek bir kanala aktaran bir ağaç oluşturabilir ve ardından okuyabilirsiniz.

+0

üzerinde etkileşimli onunla etrafında oynayabilir:

İşte tam ve kullanışlı bir örnek. – poolie

+0

Bu verilen dilim nasıl elde edersiniz? –

+0

@Matt [ephemient'in cevabı] 'na bakın (http://stackoverflow.com/questions/4220745/how-to-select-for-input-on-a-dynamic-list-of-channels-in-go/4221081#4221081). – poolie

4
package main 

import "fmt" 

func main() { 
    c1 := make(chan int) 
    c2 := make(chan int) 

    go func() { c1 <- 1 }() 
    go func() { c2 <- 2 }() 

    cs := []chan int{c1, c2} 
    cm := make(chan [2]int) 

    for idx, c := range(cs) { 
     go func(idx int, c chan int) { 
      cm <- [2]int{idx, <-c} 
     }(idx, c) 
    } 

    fmt.Print(<-cm) 
    fmt.Print(<-cm) 
} 

baskı [0 1][1 2] (veya belki [1 2][0 1]).

+0

Bu, temelde Kevin Ballard'ın söylediklerinin birçoğunu yazıyor, ancak, birçok kanaldan, statik olarak tanımlanmış bir sayıda varış noktasına kadar uzanan yeni goroutinler yapabilirsiniz. Yeterince adil. – poolie

+0

Her kanal için o kanaldan çekilen ve çoğullama kanalına koyan başka bir goroutin yaratır mısın? –

+0

@MattJoiner, doğru. Sanırım 1: 1 olması gerekmiyor, ama goroutines ucuz olduğundan, bu şekilde yapmamanın sebebi *. – poolie

0

Belki de böyle bir şey uygulanabilir mi?

// multiplex takes a slice of chan ints and returns a channel 
// that multiplexes between all of them. 
func multiplex(chs []<-chan int) <-chan int { 
    c := make(chan int) 
    d := make(chan bool) 
    for _, ch := range chs { 
     go func(ch <-chan int) { 
      for r := range ch { 
       c <- r 
      } 
      d <- true 
     }(ch) 
    } 
    go func() { 
     for i := 0; i < len(chs); i++ { 
      <-d 
     } 
     close(c) 
    }() 
    return c 
} 
5

go1.1'den bu yana, dinamik olarak seçim kümeleri yapmak için uygun bir API var.

package main 

import (
    "log" 
    "reflect" 
) 

func sendToAny(ob int, chs []chan int) int { 
    set := []reflect.SelectCase{} 
    for _, ch := range chs { 
     set = append(set, reflect.SelectCase{ 
      Dir: reflect.SelectSend, 
      Chan: reflect.ValueOf(ch), 
      Send: reflect.ValueOf(ob), 
     }) 
    } 
    to, _, _ := reflect.Select(set) 
    return to 
} 

func recvFromAny(chs []chan int) (val int, from int) { 
    set := []reflect.SelectCase{} 
    for _, ch := range chs { 
     set = append(set, reflect.SelectCase{ 
      Dir: reflect.SelectRecv, 
      Chan: reflect.ValueOf(ch), 
     }) 
    } 
    from, valValue, _ := reflect.Select(set) 
    val = valValue.Interface().(int) 
    return 
} 

func main() { 
    channels := []chan int{} 
    for i := 0; i < 5; i++ { 
     channels = append(channels, make(chan int)) 
    } 

    go func() { 
     for i := 0; i < 10; i++ { 
      x := sendToAny(i, channels) 
      log.Printf("Sent %v to ch%v", i, x) 
     } 
    }() 

    for i := 0; i < 10; i++ { 
     v, x := recvFromAny(channels) 
     log.Printf("Received %v from ch%v", v, x) 
    } 
} 

Sen bende, ben sadece doğrudan yolu olduğunu merak düşündüm the playground