我目前有一个MQTT代码,可以订阅一个主题,打印出收到的消息,然后发布有关新主题的进一步说明。 订阅/打印在一个Goroutine中完成,而发布在另一个Goroutine中完成。这是我的代码:
var wg, pg sync.WaitGroup
// All messages are handled here - printing published messages and publishing new messages
var f MQTT.MessageHandler = func(client MQTT.Client, msg MQTT.Message) {
wg.Add(1)
pg.Add(1)
go func() {
defer wg.Done()
fmt.Printf("%s\n", msg.Payload())
//fmt.Println(os.Getpid())
}()
go func(){
defer pg.Done()
message := ""
//Changing configurations
if strings.Contains(string(msg.Payload()), "arduinoLED") == true {
message = fmt.Sprintf("change configuration")
}
if strings.Contains(string(msg.Payload()), "NAME CHANGED") == true{
message = fmt.Sprintf("change back")
}
// Publish further instructions to "sensor/instruction"
token := client.Publish("sensor/instruction", 0, false, message)
//fmt.Println(os.Getpid())
token.Wait()
}()
}
func main() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
opts := MQTT.NewClientOptions().AddBroker("tcp://test.mosquitto.org:1883")
opts.SetDefaultPublishHandler(f)
// Topic to subscribe to for sensor data
topic := "sensor/data"
opts.OnConnect = func(c MQTT.Client) {
if token := c.Subscribe(topic, 0, f); token.Wait() && token.Error() != nil {
panic(token.Error())
}
}
// Creating new client
client := MQTT.NewClient(opts)
if token := client.Connect(); token.Wait() && token.Error() != nil {
panic(token.Error())
} else {
fmt.Printf("Connected to server\n")
}
wg.Wait()
pg.Wait()
<-c
}
已注释掉的os.Getpid()
行用于检查我正在运行哪个Goroutine的进程。现在它们都显示相同的数字(这意味着它们都在同一进程上运行?)。
我的问题是:如何在单独的进程上运行两个Goroutine?有办法吗?
编辑::如果无法完成此操作,我想使用渠道编写此代码。这是我的代码:
var f MQTT.MessageHandler = func(client MQTT.Client, msg MQTT.Message) {
sensorData := make(chan []byte)
wg.Add(1)
pg.Add(1)
go func() {
defer wg.Done()
//fmt.Printf("%s\n", msg.Payload())
sensorData <- string(msg.Payload())
fmt.Println(<-sensorData) //currently not printing anything
}()
go func(){
defer pg.Done()
message := ""
//Changing configurations
if strings.Contains(<-sensorData, "arduinoLED") == true{
message = fmt.Sprintf("change configuration")
}
if strings.Contains(<-sensorData, "NAME CHANGED") == true{
message = fmt.Sprintf("change back")
}
// Publish further instructions to "sensor/instruction"
token := client.Publish("sensor/instruction", 0, false, message)
token.Wait()
}()
}
但是,我无法使用通道打印任何数据。我在做什么错了?
答案 0 :(得分:5)
您可能来自Python,对吗? ;-)
它的模块名为
multiprocessing
在其stdlib中,这很可能会解释您为什么使用
您的问题标题中的这个名称,以及为什么您显然是
在解释@JimB的意思时遇到了困难
如果您需要单独的流程,则需要自己执行
问题是,Python的multiprocessing
是相当高级的
藏在里面的东西很多。
当您生成multiprocessing.Process
并使其运行时
一个函数,真正发生的是这样:
Python解释器创建另一个操作系统的
处理(使用
fork(2)
在类Unix系统上
或Windows上的CreateProcess
)并安排
也可以执行Python插入器。
关键点是您现在将有两个流程 运行两个Python插入器。
它是为Python插入程序安排的 子进程有一种与Python通信的方法 父进程中的解释器。
此“通信链接” 涉及某种形式 IPC中@JimB的引用。 根本没有其他方法可以传达数据和动作 完全是因为商品 现代操作系统提供了严格的流程分离。
exchange Python objects between the processes时,两个通信的Python
口译员将它们 serialize 和 deserialize 放在背后
通过IPC链接发送之前以及接收之后
他们从那里,相应地。
这是使用pickle
模块实现的。
Go没有任何可以直接解决的直接解决方案
与Python的multiprocessing
匹配,我真的怀疑它是否可以
已经明智地实施了。
主要原因是Go 比Python低得多,因此它没有 拥有Python的丰富经验,可以对 它所管理的价值观的类型,并且还努力拥有 尽可能减少其构造中的隐藏成本。
Go还努力避免采用“框架式”方法
解决问题,并在使用“图书馆式”解决方案时
可能。 (“框架与库”的摘要
例如here。)
Go的所有内容都在其标准库中实现
类似于Python的multiprocessing
,但没有
现成的frakework-y解决方案。
因此,您可以按照以下步骤进行操作:
使用os/exec
运行您自己的进程的另一个副本。
使用encoding/
层次结构中的任何程序包进行序列化
并在交换时反序列化数据。
“定位”解决方案据说是encoding/gob
。
发明并实施一个简单的协议来告知 子进程该做什么,用什么数据, 以及如何将结果传达回母版。
出于很多原因,我会说不,不是:
Go像可怕的GIL一样, 因此无需回避它即可实现真正的并行性 自然而然。
内存安全掌握在您手中,而实现安全 当您忠实地遵守原则时,并不难 通过渠道发送的现在由所有 接收器。 换句话说,通过通道发送值 也是这些价值的所有权转移。
Go工具链具有集成的种族检测器,因此您
可以使用-race
标志运行测试套件并创建评估
使用go build -race
进行相同的程序构建
目的:当以这种方式检测到的程序运行时,
种族检测器一检测到它就会使它崩溃
不同步的读/写内存访问。
崩溃导致的打印输出包括
关于和哪里出错的解释性消息,
带有堆栈跟踪。
IPC速度很慢,因此增益很可能会被损失抵消。
所有方面,我认为没有真正的理由分开流程,除非 您正在编写类似电子邮件处理服务器的内容 这个概念很自然地出现。
答案 1 :(得分:1)
通道用于在goroutine之间进行通信,您不应该在类似以下代码的goroutine中使用它:
sensorData <- string(msg.Payload())
fmt.Println(<-sensorData) //currently not printing anything
如果要按通道测试打印,可以在同一goroutine中使用缓冲通道以避免阻塞,如下所示:
sensorData := make(chan []byte, 1)
欢呼