在Golang中的for select中陷入无限循环。

huangapple go评论72阅读模式
英文:

Stuck in infinite loop in for select in Golang

问题

以下是我的翻译:

下面给出的代码是我使用的示例代码。我想从ch1ch2读取数据,但陷入了无限循环中。

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 &quot;fmt&quot;

func main() {
	ch1, ch2 := func() (&lt;-chan int, &lt;-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 := &lt;-ch1:
			fmt.Println(&quot;from ch1&quot;, a)
		case a := &lt;-ch2:
			fmt.Println(&quot;from ch2&quot;, a)
		default:
			fmt.Println(&quot;done&quot;)
		}
	}
}

func worker_1(ch1, ch2 chan int) {
	for i := 0; i &lt; 100; i++ {
		if i%2 == 0 {
			ch1 &lt;- i
		} else {
			ch2 &lt;- i
		}
	}
}

func worker_2(ch1, ch2 chan int) {
	for i := 101; i &lt; 200; i++ {
		if i%2 == 0 {
			ch1 &lt;- i
		} else {
			ch2 &lt;- 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 (
	&quot;fmt&quot;
	&quot;sync&quot;
)

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(&amp;wgWorkers, ch1, ch2, 0, 100)   // Worker 1
	go worker(&amp;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(&amp;wgReader, ch1, 1) // Reader 1
	go reader(&amp;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&lt;- int, from, to int) {
	// Decrement worker waitgroup counter by one when function returns
	defer wg.Done()
	for i := from; i &lt; to; i++ {
		if i%2 == 0 {
			ch1 &lt;- i
		} else {
			ch2 &lt;- i
		}
	}
}

// Reader function definition
func reader(wg *sync.WaitGroup, ch &lt;-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(&quot;from ch%d: %d\n&quot;, 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 (
&quot;fmt&quot;
&quot;sync&quot;
)
func main() {
ch1, ch2 := func() (&lt;-chan int, &lt;-chan int) {
ch_1 := make(chan int)
ch_2 := make(chan int)
var wg sync.WaitGroup
wg.Add(2)
go worker_1(&amp;wg, ch_1, ch_2)
go worker_2(&amp;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 := &lt;-ch1:
if ok {
fmt.Println(&quot;from ch1&quot;, a)
} else {
// note that channel is closed.
ch1 = nil
}
case a, ok := &lt;-ch2:
if ok {
fmt.Println(&quot;from ch2&quot;, 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 &lt; 100; i++ {
if i%2 == 0 {
ch1 &lt;- i
} else {
ch2 &lt;- i
}
}
}
func worker_2(wg *sync.WaitGroup, ch1, ch2 chan int) {
defer wg.Done()
for i := 101; i &lt; 200; i++ {
if i%2 == 0 {
ch1 &lt;- i
} else {
ch2 &lt;- i
}
}
}

huangapple
  • 本文由 发表于 2022年1月29日 03:38:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/70899385.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定