英文:
Stuck in infinite loop in for select in Golang
问题
以下是我的翻译:
下面给出的代码是我使用的示例代码。我想从ch1
和ch2
读取数据,但陷入了无限循环中。
package main
import "fmt"
func main() {
ch1, ch2 := func() (<-chan int, <-chan int) {
ch_1 := make(chan int)
ch_2 := make(chan int)
go worker_1(ch_1, ch_2)
go worker_2(ch_1, ch_2)
return ch_1, ch_2
}()
// 尝试以这种方式读取,但不起作用
for {
select {
case a := <-ch1:
fmt.Println("来自ch1", a)
case a := <-ch2:
fmt.Println("来自ch2", a)
default:
fmt.Println("完成")
}
}
}
func worker_1(ch1, ch2 chan int) {
for i := 0; i < 100; i++ {
if i%2 == 0 {
ch1 <- i
} else {
ch2 <- i
}
}
}
func worker_2(ch1, ch2 chan int) {
for i := 101; i < 200; i++ {
if i%2 == 0 {
ch1 <- i
} else {
ch2 <- i
}
}
}
希望对你有帮助!
英文:
The code given below is the sample code for my use case. I want to read data from ch1
and ch2
but got stuck into infinite loop.
package main
import "fmt"
func main() {
ch1, ch2 := func() (<-chan int, <-chan int) {
ch_1 := make(chan int)
ch_2 := make(chan int)
go worker_1(ch_1, ch_2)
go worker_2(ch_1, ch_2)
return ch_1, ch_2
}()
// trying to read this way but it is not working
for {
select {
case a := <-ch1:
fmt.Println("from ch1", a)
case a := <-ch2:
fmt.Println("from ch2", a)
default:
fmt.Println("done")
}
}
}
func worker_1(ch1, ch2 chan int) {
for i := 0; i < 100; i++ {
if i%2 == 0 {
ch1 <- i
} else {
ch2 <- i
}
}
}
func worker_2(ch1, ch2 chan int) {
for i := 101; i < 200; i++ {
if i%2 == 0 {
ch1 <- i
} else {
ch2 <- i
}
}
}
答案1
得分: 1
这是一个解决方案:
package main
import (
"fmt"
"sync"
)
func main() {
// 创建通道
ch1, ch2 := make(chan int), make(chan int)
// 创建具有计数器为2的工作组
wgWorkers := sync.WaitGroup{}
wgWorkers.Add(2)
// 运行工作协程
go worker(&wgWorkers, ch1, ch2, 0, 100) // 工作协程1
go worker(&wgWorkers, ch1, ch2, 101, 200) // 工作协程2
// 创建具有计数器为2的读取器组
wgReader := sync.WaitGroup{}
wgReader.Add(2)
// 运行读取器协程
go reader(&wgReader, ch1, 1) // 读取器1
go reader(&wgReader, ch2, 2) // 读取器2
// 等待工作协程完成
wgWorkers.Wait()
// 关闭工作协程通道
close(ch1) // 使读取器1在处理通道中的最后一个元素后退出
close(ch2) // 使读取器2在处理通道中的最后一个元素后退出
// 在退出程序之前等待两个读取器协程完成处理
wgReader.Wait()
}
// 工作协程函数定义
func worker(wg *sync.WaitGroup, ch1, ch2 chan<- int, from, to int) {
// 当函数返回时,将工作组计数器减一
defer wg.Done()
for i := from; i < to; i++ {
if i%2 == 0 {
ch1 <- i
} else {
ch2 <- i
}
}
}
// 读取器协程函数定义
func reader(wg *sync.WaitGroup, ch <-chan int, chNum int) {
// 当函数返回时,将读取器组计数器减一
defer wg.Done()
// 在这里我们迭代由工作协程1或工作协程2提供的通道。
// 通过通道的for-range循环在通道关闭时退出。
for i := range ch {
fmt.Printf("来自ch%d的值: %d\n", chNum, i)
}
}
代码注释中有解释。
英文:
Here is one solution:
package main
import (
"fmt"
"sync"
)
func main() {
// Create channels
ch1, ch2 := make(chan int), make(chan int)
// Create workers waitgroup with a counter of 2
wgWorkers := sync.WaitGroup{}
wgWorkers.Add(2)
// Run workers
go worker(&wgWorkers, ch1, ch2, 0, 100) // Worker 1
go worker(&wgWorkers, ch1, ch2, 101, 200) // Worker 2
// Create readers waitgroup with a counter of 2
wgReader := sync.WaitGroup{}
wgReader.Add(2)
// Run readers
go reader(&wgReader, ch1, 1) // Reader 1
go reader(&wgReader, ch2, 2) // Reader 2
// Wait for workers to finish
wgWorkers.Wait()
// Close workers channels
close(ch1) // Makes reader 1 exit after processing the last element in the channel
close(ch2) // Makes reader 2 exit after processing the last element in the channel
// Wait for both readers to finish processing before exiting the program
wgReader.Wait()
}
// Worker function definition
func worker(wg *sync.WaitGroup, ch1, ch2 chan<- int, from, to int) {
// Decrement worker waitgroup counter by one when function returns
defer wg.Done()
for i := from; i < to; i++ {
if i%2 == 0 {
ch1 <- i
} else {
ch2 <- i
}
}
}
// Reader function definition
func reader(wg *sync.WaitGroup, ch <-chan int, chNum int) {
// Decrement reader waitgroup counter by one when function returns
defer wg.Done()
// Here we iterate on the channel fed by worker 1 or worker 2.
// for-range on a channel exits when the channel is closed.
for i := range ch {
fmt.Printf("from ch%d: %d\n", chNum, i)
}
}
Explainations are in the code comments.
答案2
得分: 0
关闭工作完成后的通道。在两个通道都关闭后,退出接收循环。
package main
import (
"fmt"
"sync"
)
func main() {
ch1, ch2 := func() (<-chan int, <-chan int) {
ch_1 := make(chan int)
ch_2 := make(chan int)
var wg sync.WaitGroup
wg.Add(2)
go worker_1(&wg, ch_1, ch_2)
go worker_2(&wg, ch_1, ch_2)
// 在goroutine完成后关闭通道。
go func() {
wg.Wait()
close(ch_1)
close(ch_2)
}()
return ch_1, ch_2
}()
// 当仍然有打开的通道时...
for ch1 != nil || ch2 != nil {
select {
case a, ok := <-ch1:
if ok {
fmt.Println("来自ch1", a)
} else {
// 注意通道已关闭。
ch1 = nil
}
case a, ok := <-ch2:
if ok {
fmt.Println("来自ch2", a)
} else {
// 注意通道已关闭。
ch2 = nil
}
}
}
}
func worker_1(wg *sync.WaitGroup, ch1, ch2 chan int) {
defer wg.Done()
for i := 0; i < 100; i++ {
if i%2 == 0 {
ch1 <- i
} else {
ch2 <- i
}
}
}
func worker_2(wg *sync.WaitGroup, ch1, ch2 chan int) {
defer wg.Done()
for i := 101; i < 200; i++ {
if i%2 == 0 {
ch1 <- i
} else {
ch2 <- i
}
}
}
英文:
Close the channels when the workers are done. Break out of the receive loop after both channels are closed.
package main
import (
"fmt"
"sync"
)
func main() {
ch1, ch2 := func() (<-chan int, <-chan int) {
ch_1 := make(chan int)
ch_2 := make(chan int)
var wg sync.WaitGroup
wg.Add(2)
go worker_1(&wg, ch_1, ch_2)
go worker_2(&wg, ch_1, ch_2)
// Close channels after goroutiens complete.
go func() {
wg.Wait()
close(ch_1)
close(ch_2)
}()
return ch_1, ch_2
}()
// While we still have open channels ...
for ch1 != nil || ch2 != nil {
select {
case a, ok := <-ch1:
if ok {
fmt.Println("from ch1", a)
} else {
// note that channel is closed.
ch1 = nil
}
case a, ok := <-ch2:
if ok {
fmt.Println("from ch2", a)
} else {
// note that channel is closed.
ch2 = nil
}
}
}
}
func worker_1(wg *sync.WaitGroup, ch1, ch2 chan int) {
defer wg.Done()
for i := 0; i < 100; i++ {
if i%2 == 0 {
ch1 <- i
} else {
ch2 <- i
}
}
}
func worker_2(wg *sync.WaitGroup, ch1, ch2 chan int) {
defer wg.Done()
for i := 101; i < 200; i++ {
if i%2 == 0 {
ch1 <- i
} else {
ch2 <- i
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论