我有2个模块(module1和module2),其中我在module1中生成一些随机数,并将其通过main中定义的通道传递给module2。当值进入模块2时,我希望将其循环打印,直到新的值再次从module1到达为止。这是代码。
[main.go
文件内容
package main
import (
"time"
"example/module1"
"example/module2"
)
func main() {
ints := make(chan []int, 1)
for {
select {
case <- time.After(5 * time.Second):
go module1.GenerateRandint(ints)
case <- module2.Done:
go module2.Start(ints)
}
}
}
module1
的内容如下。
package module1
import (
"math/rand"
"time"
)
func GenerateRandint(a chan []int){
var rint []int
for i:=0;i<1;i++ {
rand.Seed(time.Now().UnixNano())
rint = append(rint, rand.Int())
}
a <- rint
}
module2
是:
package module2
import (
"fmt"
"math/rand"
"sync"
"time"
)
var Done = make(chan struct{})
var quit = make(chan struct{})
type localData struct {
nums []int
Lock sync.RWMutex
}
var store localData
func init() {
go func() {
Done <- struct{}{}
quit <- struct{}{}
}()
go printer(0, quit)
}
func printer(id int, quit chan struct{}) {
for {
select {
case <-quit:
return
default:
store.Lock.RLock()
fmt.Println("ID:", id, "====", store.nums)
time.Sleep(500 * time.Millisecond)
store.Lock.RUnlock()
}
}
}
func Start(a chan []int) {
rand.Seed(time.Now().UnixNano())
d := <-a
fmt.Println("RECEIVED DATA", d)
store.Lock.Lock()
go func() {
quit <- struct{}{}
}()
store.nums = d
store.Lock.Unlock()
go printer(rand.Int(), quit)
Done <- struct{}{}
}
在最终输出中,我看不到printer
功能连续打印切片。它打印一次。我在下面粘贴示例输出。
ID: 0 ==== []
RECEIVED DATA [5183630848712612481]
ID: 2057228961822266542 ==== [5183630848712612481]
RECEIVED DATA [7203870927705193095]
RECEIVED DATA [1478549829208931483]
ID: 2311909806311895805 ==== [1478549829208931483]
RECEIVED DATA [3000658591728341557]
理想的输出应该是:
ID: 0 ==== []
RECEIVED DATA [5183630848712612481]
ID: 2057228961822266542 ==== [5183630848712612481]
ID: 2057228961822266542 ==== [5183630848712612481]
ID: 2057228961822266542 ==== [5183630848712612481]
ID: 2057228961822266542 ==== [5183630848712612481]
ID: 2057228961822266542 ==== [5183630848712612481]
RECEIVED DATA [7203870927705193095]
ID: 3052382001843759201 ==== [7203870927705193095]
ID: 3052382001843759201 ==== [7203870927705193095]
ID: 3052382001843759201 ==== [7203870927705193095]
ID: 3052382001843759201 ==== [7203870927705193095]
ID: 3052382001843759201 ==== [7203870927705193095]
RECEIVED DATA [1478549829208931483]
ID: 3850200927174591249 ==== [1478549829208931483]
ID: 3850200927174591249 ==== [1478549829208931483]
ID: 3850200927174591249 ==== [1478549829208931483]
ID: 3850200927174591249 ==== [1478549829208931483]
ID: 3850200927174591249 ==== [1478549829208931483]
RECEIVED DATA [3000658591728341557]
我假设您正在询问有关go printer(0, quit)
函数中对init()
的调用的问题。之所以只打印整个列表一次,是因为以下原因:
在init()函数中,您试图将数据发送到Done
和quit
通道。现在,它们显然会阻塞,直到接收器准备就绪为止。装入模块后,接收器尚未准备好,因此您可以使用打印机方法进入default
情况。因此,它将打印该语句一次,然后进入睡眠状态500毫秒。在此期间,main()
启动并为Done
通道创建一个接收器。这将取消阻止对该通道的写入,并随后也写入quit
通道。现在,由于quit
也有数据,因此printer
方法中的select语句仅返回而不再打印。
您无法杀死goroutine:没有kill
或murder
功能。即使有一个,goroutine也没有name,也没有用户可访问的线程ID。因此,杀死一个特定 goroutine的唯一方法是谋杀all goroutine,例如通过os.Exit
或从os.Exit
返回的核爆炸摧毁整个世界。
goroutine can
可以通过从其初始函数返回或调用main
正常退出,因此,您需要做的是安排循环在其停止处停止。自己的:我有2个模块(module1和module2),其中我在module1中生成一些随机数,并将其通过main中定义的通道传递给module2。当这些值落入模块2中时,我希望将其循环打印,直到新的值再次从module1到达为止。]
您的实际代码看起来非常奇怪。例如,在Go中发信号通知某事“完成”通常是通过一个简单的
closed
通道来处理的,而不是在上面发送数据:runtime.Goexit
这特别有效,因为关闭事件实际上是广播给多个频道的读者:
runtime.Goexit
例如,您的模块退出。此外,在我看来,逻辑安排将像这样(doneChan := make(chan struct{}) // ... close(doneChan) // tell everyone we are done
可以使用这种方法告诉both
doneChan := make(chan struct{})
go f1(doneChan)
go f2(doneChan)
// ...
go fN(doneChan)
// ...
close(doneChan) // tells f1, f2, ..., fN we are done
)。我们从只有一个职责的生成函数开始:生成一片随机数并将其发送,在被告知退出时退出:main
然后,我们有一个循环使用这些函数的函数,直到被告知退出为止。它还通过see complete Playground version指示实际完成的时间,以便其调用者可以告诉它真正完成的时间。请注意,我删除了所有全局变量和花式// it's not clear why `a` is `[]int` when there is only one func GenerateRandints(a chan<- []int, done <-chan struct{}) { rand.Seed(time.Now().UnixNano()) for { rint := []int{rand.Int()} select { case a <- rint: case <-done: return } } }
函数以及互斥锁。大概在真实的代码中,它们有一定的用途,您可能需要将它们中的一些或全部放回原处。sync.WaitGroup函数,另一个具有随机数ID的函数。我保留了init
并在此处简单地将零硬编码。)
Printer
最后,我们需要fmt.Println
来驱动动作。我在这里补了一个;您真正的人无疑会有所不同:
[当该程序在Go操场上运行时,它等待一秒钟,打印complete program,然后以运行时异常(func UseRandints(wg *sync.WaitGroup, a <-chan []int, done <-chan struct{}) { defer wg.Done() var r []int for { select { case r = <-a: case <-done: return default: if r != nil { fmt.Println("ID:", 0, "====", r) } time.Sleep(500 * time.Millisecond) } } }
请注意,调用
1main
与仅返回之间有一些细微的差异。将其转换为func main() { ints := make(chan []int) done := make(chan struct{}) go GenerateRandints(ints, done) var wg sync.WaitGroup wg.Add(1) go UseRandints(&wg, ints, done) // wait 5 seconds then tell everyone to quit <-time.After(5 * time.Second) close(done) // wait for UseRandints() to signal that it's done wg.Wait() }
可显示效果(尽管从技术上讲这里有比赛):
runtime.Goexit
func main() {
go f1()
runtime.Goexit()
}
func f1() {
time.Sleep(time.Second)
fmt.Println("f1 finished")
runtime.Goexit()
}
)终止,因为所有goroutine均已退出。f1 finished
:此程序立即退出,不打印fatal error: no goroutines (main called runtime.Goexit) - deadlock!
,也没有任何运行时错误。这是因为调用Commenting out theruntime.Goexit()
call inmain
produces a program that behaves differently意味着我们永远不会经历runtime.Goexit()
返回所执行的“杀死所有其他goroutines”代码路径。
main
Module2文件已更改为如下所示。
f1 finished