我正在使用Go语言处理数据导入作业,我想将每个步骤编写为闭包,并使用通道进行通信,即每个步骤都是并发的。问题可以通过以下结构来定义。
出于这个问题的目的,我只处理必须在新的小部件上采取的前三个步骤。我假设在此基础上,第四步可以实现为一个管道步骤,它本身是用一个子三步管道实现来控制* WidgetRevision * s
为此,我一直在编写一些代码来为我提供以下API:
// A Pipeline is just a list of closures, and a smart
// function to set them all off, keeping channels of
// communication between them.
p, e, d := NewPipeline()
// Add the three steps of the process
p.Add(whizWidgets)
p.Add(popWidgets)
p.Add(bangWidgets)
// Start putting things on the channel, kick off
// the pipeline, and drain the output channel
// (probably to disk, or a database somewhere)
go emit(e)
p.Execute()
drain(d)
我已经实现了它(代码位于Gist或Go Playground),但它已经死锁,100%成功失败率
在调用p.Execute()
时出现死锁,因为可能其中一个频道最终没有任何事情可做,任何一个都没有被发送,也没有工作要做......
向emit()
和drain()
添加几行调试输出,我看到以下输出,我相信闭包调用之间的流水线是正确的,我看到一些小部件被省略。
Emitting A Widget
Input Will Be Emitted On 0x420fdc80
Emitting A Widget
Emitting A Widget
Emitting A Widget
Output Will Drain From 0x420fdcd0
Pipeline reading from 0x420fdc80 writing to 0x420fdd20
Pipeline reading from 0x420fdd20 writing to 0x420fddc0
Pipeline reading from 0x420fddc0 writing to 0x42157000
以下是我对此方法的一些了解:
Pipeline.Process(*Widget)
interface{}
类型是解决方案,我不知道去得好以确定它是否是是否合理。总结:如何修复此代码,应该我修复此代码,如果你是一个比我更有经验的程序员,你会如何解决这个问题? “顺序工作单位”问题?
答案 0 :(得分:2)
我只是觉得我不会建立远离频道的抽象。显式管道。
你可以很容易地为所有实际的管道操作创建一个函数,看起来像这样:
type StageMangler func(*Widget)
func stage(f StageMangler, chi <-chan *Widget, cho chan<- *Widget) {
for widget := range chi {
f(widget)
cho <- widget
}
close(cho)
}
然后你可以传递func(w *Widget) { w.Whiz = true}
或类似的舞台建设者。
此时您的add
可能会收集这些内容以及他们的工作人员数量,因此特定阶段可以更轻松地拥有 n 工作人员。
我不确定这比直接拼接通道更容易,除非你在运行时构建这些管道。