Golang中select语句无法通过channel发送数据的问题如何解决?

Golang中select语句无法通过channel发送数据的问题如何解决?

package main 

import (
	"fmt"
	"time")

func useChan(dataChan <-chan string,stopchan <-chan string){
	for{
		select{
			case <- dataChan:
				fmt.Println("data Recieved")
				time.Sleep(50 * time.Millisecond)
			case <- stopchan:
				fmt.Println("stopping")
				return
			default:
				continue
		}
	}
}

func main() {
	dataChan := make(chan string)
	stopchan := make(chan string)
	go useChan(dataChan,stopchan)
	//ready := true
	for timeout := time.After(5 *time.Second); ;{
		time.Sleep(10 * time.Millisecond)
		select{
		case dataChan <-"something":
		case <-timeout:
			stopchan <- "stop"
			fmt.Println("breaking ")
			return
		default:
			//fmt.Println("continue")
			
			continue

		}
	}
	
}

请帮助我


更多关于Golang中select语句无法通过channel发送数据的问题如何解决?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

9 回复

尝试从 select 块中移除两个默认情况。并保持无缓冲通道。

更多关于Golang中select语句无法通过channel发送数据的问题如何解决?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你期望发生什么?实际发生了什么?是否出现错误?

select case 基本上是随机的,但并非完全随机 😊

我期望它能打印"数据已接收"。但它没有打印出来。运行时没有错误。

请查看关于如何在 select 语句中使用 time.After 的文档:

https://golang.org/pkg/time/#After

好的,程序运行了,但在 useChan 函数中的"data received"没有打印出来。 这是一个学习练习。存在一些逻辑错误。

// 代码部分保持原样

好的,我明白了。感谢您的回复,但显然当我将无缓冲通道改为大小为1的缓冲通道时,它就能正常工作了。

例如:

dataChan := make(chan string,1)
stopchan := make(chan string,1)

但我不知道其中的原因。 能否请您解释一下这种行为?谢谢

天啊,它居然成功了。

以下是我的理解,请告诉我是否正确:

无缓冲通道的写入操作是阻塞的,除非有协程正在从中读取。由于在 Select 语句中,当多个 case 条件为真时,case 选择是随机的,所以它选择了 default case。但我仍然不明白的是,既然选择 default 和其他通道的概率相同,为什么它甚至一次都没有从 “dataChan” 中读取过。

谢谢

在你的代码中,select 语句无法通过 channel 发送数据的问题主要源于 useChan 函数中的 default 分支。由于 default 分支的存在,当 dataChan 和 stopchan 都没有数据可接收时,useChan 函数会立即执行 default 分支并继续循环,这导致它无法及时接收来自 main 函数发送的数据。此外,main 函数中的 default 分支也导致发送操作被跳过。以下是修改后的代码示例,解决了这些问题:

package main

import (
	"fmt"
	"time"
)

func useChan(dataChan <-chan string, stopchan <-chan string) {
	for {
		select {
		case <-dataChan:
			fmt.Println("data Received")
			time.Sleep(50 * time.Millisecond)
		case <-stopchan:
			fmt.Println("stopping")
			return
		}
	}
}

func main() {
	dataChan := make(chan string)
	stopchan := make(chan string)
	go useChan(dataChan, stopchan)

	timeout := time.After(5 * time.Second)
	for {
		select {
		case dataChan <- "something":
			time.Sleep(10 * time.Millisecond)
		case <-timeout:
			stopchan <- "stop"
			fmt.Println("breaking")
			return
		}
	}
}

修改说明:

  • 在 useChan 函数中,移除了 default 分支。这样,select 语句会阻塞等待 dataChan 或 stopchan 的数据,确保能及时接收发送的操作。
  • 在 main 函数中,移除了 default 分支和多余的 continue 语句。现在,select 会阻塞直到 dataChan 发送成功或超时触发,避免了发送操作被跳过。
  • 调整了超时逻辑,使用 time.After 在 select 中直接处理超时事件。

运行此代码后,main 函数会成功通过 dataChan 发送数据,useChan 函数能正常接收并打印 “data Received”,在5秒超时后发送停止信号并退出。

回到顶部