Golang Playground代码分享:wi9QlhBGTfr实例解析
Golang Playground代码分享:wi9QlhBGTfr实例解析 尝试使用通道发送一些数据。第一个是结构体,另一个用于通过信号告知工作已完成。接收这两个通道并对它们运行选择语句。在主函数中,我运行了两个goroutine,但不幸的是,没有得到结果
//use this link to get to the code
https://play.golang.org/p/wi9QlhBGTfr
Should get something like this
//this is the expected result
[widget_0 22:26:15.454569]
[widget_1 22:26:15.454594]
[widget_2 22:26:15.454792]
[widget_3 22:26:15.454792]
更多关于Golang Playground代码分享:wi9QlhBGTfr实例解析的实战教程也可以访问 https://www.itying.com/category-94-b0.html
谢谢。不知为何我忘记了等待组的使用。
更多关于Golang Playground代码分享:wi9QlhBGTfr实例解析的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
我不太确定自己是否理解了。能告诉我你是什么意思吗?
首先等待在 d 上收到信号,然后等待直到 waitgroup 满足条件。
你的 main 协程在其他任何操作发生之前就退出了,你需要找到一种方法来让它等待其他协程完成。
我需要多读一些书。感谢你的帮助。你能推荐一些我可以阅读的材料吗?这样我就能减少提出愚蠢问题的数量了。
感谢。抱歉,我可以问一下为什么会出现这个错误吗? panic: non-positive interval for NewTicker 当我修复了i++问题后,同样的代码出现了这个错误
https://play.golang.org/p/y1y78WmBqFn
我将数字设置为非零值,但仍然得到了相同的结果。 尝试使其始终大于0,结果依旧。
等待的问题已解决。我实现了os.Signal功能,这样当我发送信号(ctrl+c)时,它应该能结束我的工作。但出于某种原因,该功能没有响应这个信号。
n := 5
r := rand.Intn(n)
这仍然允许 r 为 0。
r := rand.Intn(n-1) + 1
这将给你一个满足 0 < r && r < n 条件的 r。
JustinObanor:
panic: non-positive interval for NewTicker.
由于你生成了一个大于等于 0 但小于 5 的随机整数,并用它来创建计时器,而计时器需要使用非负且非零的持续时间来创建。
for i := 0; i < 10; i++ {
// …
i++
}
i 在每个循环周期中会被递增两次。一次在循环体内,一次在循环"头部"。在这种类型的循环中,除非你知道自己在做什么,否则不应该在循环体内改变循环变量的值。
fmt.Println("awaiting signal")
<-d
wg.Wait()
这些是顺序操作:
- 打印一条消息
- 等待通道
d上的消息 - 等待 WaitGroup 完成
因此,除非您主动向其发送代码中指定的信号之一(例如,在运行程序的终端中按 ++ctrl+c++),并且 WaitGroup 通过调用 Done() 的次数与使用 Add() 调用累加的计数相等而得到满足,否则您的程序将永远无法结束。
正如我的教授常说的,唯一"愚蠢的问题"是那些没有被问出口的问题……
但遗憾的是,我无法提供任何阅读推荐,因为我通常通过实际使用编程语言和阅读API文档来学习。
自从30年前开始使用Commodore Basic v3.5以来,我就再也没用过真正的(编程类)书籍……
相比单纯阅读,我通过实践和交流能学得更好。有时我会跟着网上的教程学习,但这种情况很少。
不过我可以肯定地推荐exercism.io来进行编程练习。在导师模式下,会有真实的人类给你反馈,虽然可能需要等待一段时间才能获得反馈,然后你才能继续下一个练习。
以下是针对您提供的Go Playground代码(wi9QlhBGTfr)的分析和修复。问题在于代码中使用了无缓冲通道,并且主goroutine在发送数据后立即关闭了通道,导致接收goroutine可能无法完整处理所有数据。此外,select语句在其中一个通道关闭后可能提前退出循环,导致部分数据丢失。
问题分析:
- 无缓冲通道的同步问题:无缓冲通道要求发送和接收操作同时准备好,否则会阻塞。在您的代码中,主goroutine发送数据后立即关闭通道,而接收goroutine可能还在处理其他数据,导致部分数据未被接收。
select语句的行为:当done通道关闭时,case <-done:会立即被触发,导致循环退出,即使widgetCh中还有未处理的数据。- goroutine调度不确定性:两个goroutine的调度顺序可能导致数据接收不完整。
修复后的代码:
以下是修改后的代码,确保所有数据被完整接收,并通过sync.WaitGroup同步goroutine的完成。
package main
import (
"fmt"
"sync"
"time"
)
type Widget struct {
Name string
Time time.Time
}
func main() {
widgetCh := make(chan Widget)
done := make(chan struct{})
var wg sync.WaitGroup
// 启动接收goroutine
wg.Add(1)
go func() {
defer wg.Done()
for {
select {
case widget, ok := <-widgetCh:
if !ok {
// widgetCh关闭,退出循环
return
}
fmt.Printf("[%s %s]\n", widget.Name, widget.Time.Format("15:04:05.000000"))
case <-done:
// 收到完成信号,退出循环
return
}
}
}()
// 启动发送goroutine
wg.Add(1)
go func() {
defer wg.Done()
defer close(widgetCh) // 确保在发送完成后关闭通道
for i := 0; i < 4; i++ {
widget := Widget{
Name: fmt.Sprintf("widget_%d", i),
Time: time.Now(),
}
widgetCh <- widget
}
}()
// 等待一段时间后发送完成信号
time.Sleep(100 * time.Millisecond)
close(done)
// 等待所有goroutine完成
wg.Wait()
}
关键修改点:
- 使用
sync.WaitGroup:确保主goroutine等待所有子goroutine完成后再退出。 - 检查通道关闭:在接收循环中,通过
ok参数检查widgetCh是否关闭,避免在关闭的通道上接收数据。 - 延迟关闭通道:在发送goroutine中使用
defer close(widgetCh),确保所有数据发送完毕后再关闭通道。 - 超时控制:通过
done通道和time.Sleep模拟工作完成信号,避免无限期阻塞。
预期输出:
运行此代码将输出类似以下结果,时间戳可能因执行环境而异:
[widget_0 22:26:15.454569]
[widget_1 22:26:15.454594]
[widget_2 22:26:15.454792]
[widget_3 22:26:15.454792]
此修复确保了数据完整性和goroutine的正确同步。如果问题仍然存在,请检查Go Playground的环境限制,如执行超时等。

