Ответ 1
Мне нравится @tux21b answer; наличие канала, созданного в функции fib()
, делает код вызова приятным и чистым. Чтобы разработать немного, вам нужен только отдельный канал "выйти", если нет возможности сообщить функции, когда останавливаться при ее вызове. Если вы только заботитесь о "числах до X", вы можете сделать это:
package main
import "fmt"
func fib(n int) chan int {
c := make(chan int)
go func() {
x, y := 0, 1
for x < n {
c <- x
x, y = y, x+y
}
close(c)
}()
return c
}
func main() {
// Print the Fibonacci numbers less than 500
for i := range fib(500) {
fmt.Println(i)
}
}
Если вам нужна возможность сделать это, это немного небрежно, но мне лично это нравится лучше, чем тестирование условия в вызывающем, а затем сигнализация о выходе из отдельного канала:
func fib(wanted func (int, int) bool) chan int {
c := make(chan int)
go func() {
x, y := 0, 1
for i := 0; wanted(i, x); i++{
c <- x
x, y = y, x+y
}
close(c)
}()
return c
}
func main() {
// Print the first 10 Fibonacci numbers
for n := range fib(func(i, x int) bool { return i < 10 }) {
fmt.Println(n)
}
// Print the Fibonacci numbers less than 500
for n := range fib(func(i, x int) bool { return x < 500 }) {
fmt.Println(n)
}
}
Я думаю, что это зависит только от особенностей данной ситуации:
- Сообщите генератору, когда нужно остановиться, когда вы его создаете
- Передача явного количества значений для генерации
- Передача значения цели
- Передача функции, которая определяет, продолжать ли
- Дайте генератору канал "quit", проверьте значения самостоятельно и сообщите ему, чтобы он ушел, когда это необходимо.
Завершить и ответить на ваши вопросы:
-
Увеличение размера канала поможет повысить производительность из-за меньшего количества переключателей контекста. В этом тривиальном примере ни производительность, ни потребление памяти не будут проблемой, но в других ситуациях буферизация канала часто является очень хорошей идеей. В большинстве случаев память, используемая
make (chan int, 100)
, вряд ли кажется значимой, но она может легко сделать большую разницу в производительности. -
У вас есть бесконечный цикл в вашей функции
fibonacci
, так что запущенный в него goroutine будет запускаться (блокировать наc <- x
, в данном случае) навсегда. Тот факт, что (однаждыc
выходит за пределы области действия в вызывающем абоненте), вы больше никогда не будете читать из канала, который вы делитесь с ним, и не меняет этого. И, как отметил @tux21b, канал никогда не будет собираться с мусором, поскольку он все еще используется. Это не имеет никакого отношения к закрытию канала (цель которого - позволить получающему концу канала знать, что больше не будет больше значений) и все, что нужно сделать, чтобы не возвращаться из вашей функции.