如何 运行 goroutine 的单实例
How to run single instance of goroutine
我有一个 goroutine 会 运行 多次。但它一次只能 运行 一个(单个实例)。 correct/idiomatic 确保某个 goroutine 一次只能 运行 一个的方法是什么?
这是我设计的示例代码来说明这一点:
func main() {
// Contrived example!!!!!!
// theCaller() may be run at multiple, unpredictable times
// theJob() must only be run one at a time
go theCaller()
go theCaller()
go theCaller()
}
func theCaller() {
if !jobIsRunning { // race condition here!
jobIsRunning = true
go theJob()
}
}
var jobIsRunning bool
// Can run multiple times, but only one at a time
func theJob() {
defer jobDone()
do_something()
}
func jobDone() {
jobIsRunning = false
}
根据 OP 的问题和其他评论,目标似乎是开始一份新工作,当且仅当工作尚未 运行。
使用受sync.Mutex保护的布尔变量来记录作业的运行状态。在开始作业时将变量设置为 true,在作业完成时将变量设置为 false。测试此变量以确定是否应启动作业。
var (
jobIsRunning bool
JobIsrunningMu sync.Mutex
)
func maybeStartJob() {
JobIsrunningMu.Lock()
start := !jobIsRunning
jobIsRunning = true
JobIsrunningMu.Unlock()
if start {
go func() {
theJob()
JobIsrunningMu.Lock()
jobIsRunning = false
JobIsrunningMu.Unlock()
}()
}
}
func main() {
maybeStartJob()
maybeStartJob()
maybeStartJob()
}
也可以使用较低级别的 sync/atomic 包,并且可能比使用互斥体具有更好的性能。
var jobIsRunning uint32
func maybeStartJob() {
if atomic.CompareAndSwapUint32(&jobIsRunning, 0, 1) {
go func() {
theJob()
atomic.StoreUint32(&jobIsRunning, 0)
}()
}
}
sync/atomic 包文档警告包中的函数需要非常小心才能正确使用,并且大多数应用程序应该使用 sync 包。
我有一个 goroutine 会 运行 多次。但它一次只能 运行 一个(单个实例)。 correct/idiomatic 确保某个 goroutine 一次只能 运行 一个的方法是什么?
这是我设计的示例代码来说明这一点:
func main() {
// Contrived example!!!!!!
// theCaller() may be run at multiple, unpredictable times
// theJob() must only be run one at a time
go theCaller()
go theCaller()
go theCaller()
}
func theCaller() {
if !jobIsRunning { // race condition here!
jobIsRunning = true
go theJob()
}
}
var jobIsRunning bool
// Can run multiple times, but only one at a time
func theJob() {
defer jobDone()
do_something()
}
func jobDone() {
jobIsRunning = false
}
根据 OP 的问题和其他评论,目标似乎是开始一份新工作,当且仅当工作尚未 运行。
使用受sync.Mutex保护的布尔变量来记录作业的运行状态。在开始作业时将变量设置为 true,在作业完成时将变量设置为 false。测试此变量以确定是否应启动作业。
var (
jobIsRunning bool
JobIsrunningMu sync.Mutex
)
func maybeStartJob() {
JobIsrunningMu.Lock()
start := !jobIsRunning
jobIsRunning = true
JobIsrunningMu.Unlock()
if start {
go func() {
theJob()
JobIsrunningMu.Lock()
jobIsRunning = false
JobIsrunningMu.Unlock()
}()
}
}
func main() {
maybeStartJob()
maybeStartJob()
maybeStartJob()
}
也可以使用较低级别的 sync/atomic 包,并且可能比使用互斥体具有更好的性能。
var jobIsRunning uint32
func maybeStartJob() {
if atomic.CompareAndSwapUint32(&jobIsRunning, 0, 1) {
go func() {
theJob()
atomic.StoreUint32(&jobIsRunning, 0)
}()
}
}
sync/atomic 包文档警告包中的函数需要非常小心才能正确使用,并且大多数应用程序应该使用 sync 包。