Как уже отмечали другие, вы можете решить эту проблему намного проще:
type sized struct {
url string
length int
err error
}
func sizer(url string, result chan<- sized, wg *sync.WaitGroup) {
defer wg.Done()
length, err := getPage(url)
result <- sized{url, length, err}
}
func main() {
urls := []string{"http://www.google.com/", "http://www.yahoo.com",
"http://www.bing.com", "http://bbc.co.uk"}
ch := make(chan sized)
var wg sync.WaitGroup
for _, url := range urls {
wg.Add(1)
go sizer(url, ch, &wg)
}
go func() {
wg.Wait()
close(ch)
}()
for result := range ch {
if result.err != nil {
fmt.Printf("%s: %s\n", result.url, result.err)
} else {
fmt.Printf("%s: length = %d\n", result.url, result.length)
}
}
}
Полный пример на игровой площадке, хотя он не может дозвониться, поэтому там не очень полезно.
Как осуществлять двунаправленную связь по каналу?
Нельзя.
Ну, это не совсем так. Скажем вместо этого: вы не должны .
Предположим, у нас есть канал:
var ch chan T
для некоторого типа T.
The канал по своей сути ... ну, я думаю, ненаправленный - правильное слово:
- любой может поставить любое значение введите T в канал с помощью
ch <- val
- любой может взять любое значение типа T из канала с помощью
var <- ch
Это явно не t однонаправленный, но я думаю, что называть его двунаправленным вводит в заблуждение: у него есть стороны «положить вещи в» и «убрать вещи», обе сгруппированы в один экземпляр канала, но канал не связан с любым конкретным пользователем . Вы можете скопировать значение канала в направленный экземпляр (см. В чем смысл односторонних каналов в Go? ) в любом направлении, но на самом деле оба являются просто ссылками на базовый объект ненаправленного канала. 1 Затем вы можете передать исходный канал или его однонаправленную копию любому пользователю или рассматривать любой из них как «глобальный» "(широкие) переменные, которые может использовать каждый.
Теперь давайте добавим две сущности, которые мы назовем X и Y. Если канал ch
имеет буферизованный , один или оба из X и Y могут вставлять предметы, а затем один или оба из A и B могут вынимать предметы. Элементы будут появляться в том порядке, в котором они были, с сериализацией доступа; если канал заполнен, то попытка вставить элемент будет заблокирована; но элементы не передаются специально из X в Y. В частности:
// Y: paused or stopped
// do this in X when ch is initially empty:
ch <- T{}
v := <-ch
Здесь X помещает нулевое значение T
в канал, затем забирает обратно. Это не направлено. X получил свои собственные данные.
Если канал не пуст, но и не полон, X или Y могут что-то добавить к нему ( как очередь), затем снимите что-нибудь с начала очереди. Но это просто использование канала как очереди. (См. Можно ли использовать буферизованный канал Go в качестве потокобезопасной очереди? )
Если бы эта очередь имела определенные функции, которых ей определенно не хватает, вы могли бы использовать единственная очередь для своего рода двунаправленной связи (см. Возможна ли двусторонняя связь с использованием единственной очереди сообщений в C). Но их там нет. Если вам действительно нужна двунаправленная связь, ответ очевиден: используйте две очереди. Назначьте одну очередь - один канал - как канал X-отправляет-на-Y, а другой - как канал Y-отправляет-к-X.
1 Базовый канал доступен / восстанавливается через unsafe
, но не делайте этого, если вы действительно не знаете, что делаете. Кто-то, кто передал вам однонаправленный экземпляр, вероятно, не намерен, чтобы вы использовали другую «сторону» канала.