gpt4 book ai didi

go - 在单独的进程(多处理)上运行Goroutines

转载 作者:IT王子 更新时间:2023-10-29 01:49:10 27 4
gpt4 key购买 nike

我目前有一个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?有办法吗?

编辑:如果无法完成此操作,我想使用 channel 编写此代码。这是我的代码:
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()

}()

}

但是,我无法使用 channel 打印任何数据。我究竟做错了什么?

最佳答案

您可能来自Python,对吗? ;-)

它的模块名为
multiprocessing
在其stdlib中,这很可能会解释您为什么使用
您的问题标题中的这个名称,以及为什么您显然
在解释@JimB的意思时遇到了麻烦

If you need a separate process, you need to exec it yourself



Python中的“多处理”

事实是,Python的 multiprocessing是相当高级的
藏在里面的东西很多。
当您生成 multiprocessing.Process并使其运行时
一个函数,真正发生的是这样的:
  • Python解释器创建另一个操作系统的
    处理(使用
    类似于Unix的系统上的 fork(2)
    或Windows上的 CreateProcess )并安排
    也可以执行Python插入器

    关键点是您现在将有两个过程
    运行两个Python插入器。
  • 它是为Python插入程序安排的。
    子进程有一种与Python通信的方法
    父进程中的解释器。

    此“通信链接”必然涉及某种形式
    IPC @JimB的引用。
    根本没有其他方法可以传达数据和 Action
    恰恰是因为一种商品
    现代OS提供了严格的流程分离。
  • 当您exchange Python objects between the processes时,两个通信的Python
    口译员在后台对它们进行序列化和反序列化
    通过IPC链接发送之前以及接收之后
    他们从那里,相应地。
    这是使用 pickle 模块实现的。

  • 回去

    Go没有任何可以直接解决的直接解决方案
    匹配Python的 multiprocessing,我真的怀疑它是否可以
    已经明智地实现了。

    造成这种情况的主要原因主要是因为Go
    比Python低得多,因此它没有
    拥有Python做出纯粹假设的奢侈
    它所管理的值(value)观的类型,并且还努力拥有
    尽可能减少其构造中的隐藏成本。

    Go还努力避免采用“框架式”方法
    解决问题,并在使用“图书馆式”解决方案时
    可能的。 (“框架与库”的简要介绍
    给出,例如 here。)
    Go的所有内容都在其标准库中实现
    类似于Python的 multiprocessing,但没有
    现成的frakework-y解决方案。

    因此,您可以按照以下步骤进行操作:
  • 使用os/exec运行您自己的进程的另一个副本。
  • 确保生成的进程“知道”它已启动
    在特殊的“奴隶”模式下采取相应行动。
  • 使用任何形式的IPC与新进程进行通信。
    通过standard I/O streams交换数据
    子进程的
    最简单的滚动方式(除非您需要交换
    已打开的文件,但这是一个比较麻烦的主题,所以我们不要离题。
  • 使用encoding/层次结构中的任何程序包进行序列化
    并在交换时反序列化数据。

    “Go ”解决方案据说是encoding/gob
  • 发明并实现一个简单的协议(protocol)来告知
    子进程该做什么,用什么数据,
    以及如何将结果传达回主机。

  • 真的值得麻烦吗?

    我会说不,不是,出于多种原因:
  • Go与可怕的GIL类似,
    因此无需回避它即可实现真正的并行性
    自然而然的时候。
  • 内存安全掌握在您的手中,而实现安全性就是
    当您忠实地遵守原则时,并不难
    通过 channel 发送的内容现在由拥有
    收件人。
    换句话说,通过 channel 发送值
    也是这些值(value)的所有权转移。
  • Go工具链具有集成的种族检测器,因此您
    可以使用-race标志运行您的测试套件并创建评估
    同样使用go build -race构建程序
    目的:当以这种方式检测到的程序运行时,
    种族检测器一检测到它就会使它崩溃
    不同步的读/写内存访问。
    崩溃导致的打印输出包括
    关于什么地方以及哪里出了问题的解释性消息,
    与堆栈跟踪。
  • IPC速度很慢,因此增益很可能会被损耗所抵消。

  • 总而言之,我认为没有真正的理由分开流程,除非
    您正在编写类似电子邮件处理服务器的内容
    这个概念自然而然地出现。

    关于go - 在单独的进程(多处理)上运行Goroutines,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51091526/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com