Multithreading 半异步代码逻辑
我正在努力找出一个能够将同步流与异步行为结合在一起的工作设计 我有4个组件:Multithreading 半异步代码逻辑,multithreading,asynchronous,go,goroutine,Multithreading,Asynchronous,Go,Goroutine,我正在努力找出一个能够将同步流与异步行为结合在一起的工作设计 我有4个组件: 播种机 工人 出版者 更新程序 我唯一的限制是,一旦播种机播种数据,它必须被阻塞,直到更新程序没有完全完成处理所有任务。前3个组件可以很容易地同步,但更新程序必须并行工作,否则将永远无法完成任务 因此,流程是: Seeder->Worker->Publisher->Updater->Seeder->Worker->Publisher->Updater… 这股气流必须永远旋转 种子设定和更新是针对数据库的。不幸的是,这个
Seeder->Worker->Publisher->Updater->Seeder->Worker->Publisher->Updater…
这股气流必须永远旋转
种子设定和更新是针对数据库的。不幸的是,这个特定的数据库不允许不同的设计
我能做的最好的事情就是使用sync.WaitGroup
来同步更新程序goroutines,并将其他所有内容保持在同步状态。通过通道向更新程序提供数据
这是一个简化的代码(没有错误,没有太多逻辑)
func main(){
var wg sync.WaitGroup
c:=制造(成龙结果,100)
为了{
数据:=播种机()
msgs:=工人(数据)
结果:=发布者(msgs)
对于i:=0;i<10;i++{
工作组.添加(1)
go func(){
推迟工作组完成()
数据:=很难说,因为您的代码无法编译和运行,并且不清楚如何使用c。至少有一件事是肯定的:wg应该通过引用而不是通过值传递(sync.WaitGroup有nocopy
注释)。然后,我假设您使用c将值发送到更新程序。但是您没有提供它们的代码,因此我只能猜测。例如,假设调度的发生使得前9个goroutine读取通道中的所有内容;然后,最后一个例程被永远阻止,并且永远不会释放WaitGroup。在这种情况下,一个简单的解决方案on是在最外层for循环的每次迭代中(将第3行下移两行)以及调用wg.Wait()
之前创建一个新通道。您的更新程序必须能够处理
[编辑]我想你要找的是这样的东西:
package main
import (
"fmt"
"sync"
)
// Result is a type
type Result struct {
I int
}
// Seeder is a function
func Seeder() []int {
fmt.Println("Seeding")
return []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}
}
// Worker is a function
func Worker(data []int) []int {
return data
}
// Publisher is a function
func Publisher(data []int) []Result {
var r []Result
for i := 0; i < len(data); i++ {
r = append(r, Result{I: data[i]})
}
return r
}
func updater(c chan Result, wg *sync.WaitGroup) {
for _ = range c {
// update here
wg.Done()
}
}
func main() {
var wg sync.WaitGroup
c := make(chan Result, 100)
for i := 0; i < 10; i++ {
go updater(c, &wg)
}
for {
data := Seeder()
msgs := Worker(data)
results := Publisher(msgs)
wg.Add(len(results))
for _, result := range results {
c <- result
}
wg.Wait()
}
}
主程序包
进口(
“fmt”
“同步”
)
//结果是一个类型
类型结果结构{
I int
}
//播种机是一种功能
func Seeder()[]int{
fmt.Println(“播种”)
return[]int{0,1,2,3,4,5,6,7,8,9,10,11,12,13}
}
//工人是一个函数
func Worker(数据[]整型)[]整型{
返回数据
}
//发布者是一个函数
func Publisher(数据[]int)[]结果{
var r[]结果
对于i:=0;i c代码不是要编译的。它的原始形式更复杂。我添加它是为了给出一个想法。我在这个伪代码中添加了如何从通道中提取并将WaitGroup作为指针传递。原始代码是按照它应该传递的方式传递的。我试图不在每个循环中创建新的通道,但这可能是最简单的解决方案现在开始。我也开始研究如何通过chan chan管理整个流程。你每次都创建新的Goroutine,但不想创建新的频道?为什么不?频道比Goroutine便宜得多。我也不想每次都创建Goroutine。只是不知道如何做得不同。在这种情况下,一个简单的方法就是这样做这将是使用WaitGroup来监控的不是goroutines,而是消息。我添加了一些代码来说明这一点。好吧,这还不错。我仍然需要限制更新程序中goroutines的数量,但你是对的。我不必监控它们。
package main
import (
"fmt"
"sync"
)
// Result is a type
type Result struct {
I int
}
// Seeder is a function
func Seeder() []int {
fmt.Println("Seeding")
return []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}
}
// Worker is a function
func Worker(data []int) []int {
return data
}
// Publisher is a function
func Publisher(data []int) []Result {
var r []Result
for i := 0; i < len(data); i++ {
r = append(r, Result{I: data[i]})
}
return r
}
func updater(c chan Result, wg *sync.WaitGroup) {
for _ = range c {
// update here
wg.Done()
}
}
func main() {
var wg sync.WaitGroup
c := make(chan Result, 100)
for i := 0; i < 10; i++ {
go updater(c, &wg)
}
for {
data := Seeder()
msgs := Worker(data)
results := Publisher(msgs)
wg.Add(len(results))
for _, result := range results {
c <- result
}
wg.Wait()
}
}