在Go中管理多个通道

huangapple go评论78阅读模式
英文:

Managing multiple channels in Go

问题

我是Go的新手,正在编写一个简单的Web应用程序。基本思路如下:

goroutine #1 是HTTP服务器

goroutine #2 是一个管理应用程序状态的函数。它需要定期轮询一些硬件的值,因此需要在自己的线程中运行。

当用户发出HTTP请求时,服务器将从状态goroutine请求更新的信息,然后将一个HTML页面返回给客户端。

除了一个问题,一切都运行得很好:服务器当前发送和从状态线程返回了六个不同的可能信号,每个信号都有一个请求和一个响应通道,总共有12个通道(我还打算添加至少一个或两个信号)。可能可以合并一些信号,但其中许多是不同类型的。

正如我所说,它可以工作,但变得相当混乱。

它看起来像这样:

main.go 包含实例化通道的声明:

// 关闭信号
shutdown := make(chan bool)

// 请求传感器的当前状态
sensorRequest := make(chan string)
sensorResponse := make(chan Sensor)

// 请求所有传感器的当前状态
sensorListRequest := make(chan bool)
sensorListResponse := make(chan []Sensor)

// 请求应用程序的当前状态(活动或非活动)
statusRequest := make(chan bool)
statusResponse := make(chan bool)

// 还有一些...

// 启动“状态管理器”goroutine
go ManageState(shutdown, sensorRequest, sensorResponse, sensorListRequest, sensorListResponse, statusRequest, statusResponse)

// 启动“HTTP服务器”goroutine
go ManageHTTP(shutdown, sensorRequest, sensorResponse, sensorListRequest, sensorListResponse, statusRequest, statusResponse)

所以,有几个问题:

  1. 是否有必要有单独的请求和响应通道?考虑到请求和响应是不同类型的,我看不到在两个方向上使用同一个通道的明显方法(除非使用一些技巧)。

  2. 我考虑将所有通道放入一个结构体中,可以传递给所有的goroutine,但我不确定这是否会有任何真正的好处 - 它似乎并不比我现在做的更清晰。

  3. 有没有Go的方式来做到这一点?

更新

感谢@kostya和@Aedolon建议使用sync.Mutex进行全局状态的锁定/解锁。这实际上是我的第一种方法,但我遇到了一个严重的问题:当锁释放时,我的Mutex Lock()调用随机失败无法解锁。这段代码将在树莓派上运行,我怀疑有一个错误(可能是在我用于读取硬件状态的软件包中,或者是在Go ARM二进制文件中)。但在花费了很多时间尝试追踪问题后,我决定尝试一些不同的方法。

无论如何,在多次阅读了“不要通过共享内存进行通信;相反,通过通信共享内存”(The Go Blog)之后,我决定尝试以这种方式实现。现在我正在这样做,我发现我喜欢这种方法 在Go中管理多个通道

英文:

I'm a newbie to Go & I'm writing a simple web application. The basic idea is this:

goroutine #1 is the HTTP server

goroutine #2 is a function which manages the state of the application. It needs to poll some hardware for values periodically, so it needs to run in its own thread.

When a user makes an HTTP request, the server will request updated information from the state goroutine, then return an HTML page to the client.

It all works very well except for one thing: there are currently six different possible signals sent by the server and returned from the state thread, with both a request and a response channel, for a total of 12 channels (and I'm going to be adding at least one or two more signals). It may be possible to consolidate some of the signals, but many of them are different types.

As I said, it works, but it's getting rather ugly.

It looks something like this:

main.go includes declarations to instantiate the channels:

// a shutdown signal
shutdown := make(chan bool)

// request the current state of a sensor
sensorRequest := make(chan string)
sensorResponse := make(chan Sensor)

// request the current state of ALL sensors
sensorListRequest := make(chan bool)
sensorListResponse := make(chan []Sensor)

// request the current state of the application (active or inactive)
statusRequest := make(chan bool)
statusResponse := make(chan bool)

// and a few more...

// start the "state manager" goroutine
go ManageState(shutdown, sensorRequest, sensorResponse, sensorListRequest, sensorListResponse, statusRequest, statusResponse)

// start the "HTTP server" goroutine
go ManageHTTP(shutdown, sensorRequest, sensorResponse, sensorListRequest, sensorListResponse, statusRequest, statusResponse)

So, a couple of questions:

  1. is it necessary to have separate request & response channels? Given that the request and response are different types, I can't see an obvious way to use the same channel in both directions (that isn't hacky).

  2. I considered putting all the channels into a struct which could be passed to all the goroutines, but I'm not sure that's going to be any real benefit - it doesn't seem much clearer than what I'm doing now.

  3. What is the Go way™ of doing this?

Update

Thanks to @kostya and @Aedolon for suggesting a global state with sync.Mutex for locking/unlocking. That was actually my first approach, but I ran into a serious problem: my Mutex Lock() calls were randomly failing to unblock when the lock was released. This code will be running on a Raspberry Pi, and I suspect there's a bug somewhere (either in the package I'm using to read the hardware state or in the Go ARM binaries). But after spending a bunch of time trying to trace the problem, I decided to try something different.

At any rate, after reading (many times) that I should "not communicate by sharing memory; instead, share memory by communicating" (The Go Blog), I decided to attempt to implement it this way. And now that I'm doing it this way, I find that I like this approach 在Go中管理多个通道

答案1

得分: 1

我不会完全使用通道来实现这个。

你可以从多个Go协程中更新和读取共享状态,使用sync.RWMutex进行同步。

英文:

I would not use channels for this at all.

You can update and read shared state from the same variable from multiple go-routines and use sync.RWMutex for synchronization.

huangapple
  • 本文由 发表于 2016年3月1日 23:40:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/35727109.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定