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 分支的存在,当 dataChanstopchan 都没有数据可接收时,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 语句会阻塞等待 dataChanstopchan 的数据,确保能及时接收发送的操作。
  • main 函数中,移除了 default 分支和多余的 continue 语句。现在,select 会阻塞直到 dataChan 发送成功或超时触发,避免了发送操作被跳过。
  • 调整了超时逻辑,使用 time.Afterselect 中直接处理超时事件。

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

回到顶部