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

16 回复

谢谢。不知为何我忘记了等待组的使用。

更多关于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)

这仍然允许 r0

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()

这些是顺序操作:

  1. 打印一条消息
  2. 等待通道 d 上的消息
  3. 等待 WaitGroup 完成

因此,除非您主动向其发送代码中指定的信号之一(例如,在运行程序的终端中按 ++ctrl+c++),并且 WaitGroup 通过调用 Done() 的次数与使用 Add() 调用累加的计数相等而得到满足,否则您的程序将永远无法结束。

正如我的教授常说的,唯一"愚蠢的问题"是那些没有被问出口的问题……

但遗憾的是,我无法提供任何阅读推荐,因为我通常通过实际使用编程语言和阅读API文档来学习。

自从30年前开始使用Commodore Basic v3.5以来,我就再也没用过真正的(编程类)书籍……

相比单纯阅读,我通过实践和交流能学得更好。有时我会跟着网上的教程学习,但这种情况很少。

不过我可以肯定地推荐exercism.io来进行编程练习。在导师模式下,会有真实的人类给你反馈,虽然可能需要等待一段时间才能获得反馈,然后你才能继续下一个练习。

以下是针对您提供的Go Playground代码(wi9QlhBGTfr)的分析和修复。问题在于代码中使用了无缓冲通道,并且主goroutine在发送数据后立即关闭了通道,导致接收goroutine可能无法完整处理所有数据。此外,select语句在其中一个通道关闭后可能提前退出循环,导致部分数据丢失。

问题分析:

  1. 无缓冲通道的同步问题:无缓冲通道要求发送和接收操作同时准备好,否则会阻塞。在您的代码中,主goroutine发送数据后立即关闭通道,而接收goroutine可能还在处理其他数据,导致部分数据未被接收。
  2. select语句的行为:当done通道关闭时,case <-done:会立即被触发,导致循环退出,即使widgetCh中还有未处理的数据。
  3. 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()
}

关键修改点:

  1. 使用sync.WaitGroup:确保主goroutine等待所有子goroutine完成后再退出。
  2. 检查通道关闭:在接收循环中,通过ok参数检查widgetCh是否关闭,避免在关闭的通道上接收数据。
  3. 延迟关闭通道:在发送goroutine中使用defer close(widgetCh),确保所有数据发送完毕后再关闭通道。
  4. 超时控制:通过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的环境限制,如执行超时等。

回到顶部