Возможно ли реализовать что-то похожее на yield
из python в go?То есть мне нужна парадигма производитель / потребитель, в которой потребитель может игнорировать значения, произведенные производителем, в любое время без проявления утечки памяти.
В python у меня может быть производитель, который производит бесконечные значения, и клиент можетпотреблять столько, сколько они хотят.
def producer():
i = 0
while True:
yield i
i += 1
def consumer():
for i in producer():
if i == 2:
return
Общий совет для этого заключается в том, чтобы производитель возвращал канал, который клиент использует в выражении range
, и производитель может помещать свои значения в канал.,Это нормально, если клиент считывает все значения в канале, но если клиент рано прерывает управление из цикла range
, канал производителя останется зависшим навсегда, используя память.
package main
func yield() chan int {
out := make(chan int)
go func(){
out <- 1
out <- 2
close(out)
}()
return out
}
func test(){
for _ = range yield() {
// return
}
}
func main(){
for {
test()
}
}
Если return
в test
не закомментировано, этот код будет использовать память без ограничений, потому что канал, возвращаемый yield
, имеет значение, которое ожидает чтения, и, очевидно, ни канал, ни процедура не могут быть безопасно собраны мусором.
Некоторые возможные решения (ни одно из которых мне не нравится):
Измените out
в yield
на буферизованный канал с точным количеством пространства в качестве значенийэто будет произведено.В этом случае yield
может быть
func yield () chan int {out: = make (chan int, 2) out <- 1 out <- 2 close (out) return out} </p>
Но это неоптимально, потому что я вообще не знаю, сколько произведет yield
предметов.Этот стиль похож на простой возврат массива.
Пусть метод
yield
использует тайм-аут для ввода значений в канал, а если тайм-аут достигнут, закройте канал раньше.Это делает предположения о времени выполнения клиента, что кажется плохой идеей.