Golang模式 - 第三部分
由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!
在这篇文章中,我将展示一个使用 golang channels 的很酷的模式:channels 的 channels。
通道是 Go 语言中非常灵活的工具。学会正确使用通道,就能充分发挥 Go 的强大功能。
但本文并非旨在解释什么是通道或何时需要使用通道。
如果您想了解更多关于通道的信息,我建议您阅读:
- https://blog.golang.org/share-memory-by-communicating
- https://golang.org/doc/effective_go.html#channels
- https://medium.com/rungo/anatomy-of-channels-in-go-concurrency-in-go-1ec336086adb
- https://dev.to/search?q=go%20channels
玩具问题
假设你需要定期运行某个任务,例如每秒一次。
但有时,你需要尽快运行该任务,这意味着你不能等待任务触发。
一个简单的例子是文件同步工具,它可以同步不同主机之间的文件。你希望每隔x
秒 同步一次文件,但有时你需要按需同步;也就是在预定义的计划之外强制执行同步。
通道的通道
这是解决问题的一种方法,它利用了多层渠道。
const (
running int32 = 1
notRunning int32 = 0
)
type Worker struct {
syncStrategy func() error
period time.Duration
currentStatus *int32
periodicSyncChan chan int
outOfBandSyncChan chan chan error
exitChan chan int
}
func NewSyncWorker(syncStrategy func() error, period time.Duration) *Worker {
periodicSyncChan := make(chan int)
outOfBandSyncChan := make(chan chan error)
exitChan := make(chan int)
var currentStatus = notRunning
return &Worker{
syncStrategy: syncStrategy,
period: period,
currentStatus: ¤tStatus,
periodicSyncChan: periodicSyncChan,
outOfBandSyncChan: outOfBandSyncChan,
exitChan: exitChan,
}
}
func (s *Worker) Sync() error {
if atomic.CompareAndSwapInt32(s.currentStatus, notRunning, running) {
return s.doSync()
} else {
return errors.New("Sync is already running")
}
}
func (s *Worker) doSync() error {
if e := s.syncStrategy(); e != nil {
return e
}
time.AfterFunc(s.period, func() {
s.periodicSyncChan <- 1
})
for true {
select {
case <-s.periodicSyncChan:
{
s.syncStrategy()
time.AfterFunc(s.period, func() {
s.periodicSyncChan <- 1
})
}
case responseChannel := <-s.outOfBandSyncChan:
responseChannel <- s.syncStrategy()
case <-s.exitChan:
{
atomic.CompareAndSwapInt32(s.currentStatus, running, notRunning)
return nil
}
}
}
return nil
}
func (s *Worker) OutOfBandSync() error {
responseChannel := make(chan error)
s.outOfBandSyncChan <- responseChannel
return <-responseChannel
}
func (s *Worker) Stop() {
s.exitChan <- 1
}
func (s *Worker) IsRunning() bool {
return *s.currentStatus == running
}
outOfBandSyncChan是一个通道的通道。 当客户端请求OutOfBandSync时,该函数会创建一个 responseChannel。responseChan会被添加到outOfBandSyncChan中,并在操作完成后用于返回一个值(在本例中为 nil 或错误)。
换句话说,我们是:
- 创建一个通道,用于将响应发送回客户端。
- 将新创建的通道传输到负责通过另一个通道进行同步的代码。
更重要的是,我们没有使用锁。不同的 goroutine 之间通过发送消息进行通信,这种方式非常优雅。
更多 Go 语言模式
如果你喜欢这篇文章,请查看:
你可以在Twitter和GitHub上找到我。
玩得开心!
文章来源:https://dev.to/napicella/golang-patterns-part-3-apo