如何运行goroutine的单个实例

如何运行goroutine的单个实例,go,thread-safety,goroutine,Go,Thread Safety,Goroutine,我有一个goroutine,将运行多次。但它一次只能运行一个(单个实例)。确保某个goroutine一次只能运行一个goroutine的正确/惯用方法是什么 下面是我精心设计的示例代码来说明这一点: func main() { // Contrived example!!!!!! // theCaller() may be run at multiple, unpredictable times // theJob() must only be run one at a

我有一个goroutine,将运行多次。但它一次只能运行一个(单个实例)。确保某个goroutine一次只能运行一个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的问题和其他评论,目标似乎是在作业尚未运行的情况下启动新作业

使用受保护的布尔变量来记录作业的运行状态。启动作业时将变量设置为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()
}
也可以使用较低级别的包,它可能比使用互斥锁具有更好的性能

var jobIsRunning uint32

func maybeStartJob() {
    if atomic.CompareAndSwapUint32(&jobIsRunning, 0, 1) {
        go func() {
            theJob()
            atomic.StoreUint32(&jobIsRunning, 0)
        }()
    }
}

sync/atomic包文档警告说,包中的函数需要非常小心才能正确使用,大多数应用程序都应该使用sync包

看看互斥体。牙床JimB我不知道单人飞行。我不得不研究一下,因为他们提供的例子似乎很复杂。然而,一个立即停止显示的是注释,该注释说“如果出现重复,重复调用方将等待//原始完成”。如果goroutine已经运行了,我只需要其他人说不要再尝试运行它。这对我来说确实有点像X-Y问题。。。为什么要使用例程,但强制它们按顺序运行(本质上是将并发进程转换为顺序进程?)。根据你在做什么,你可以很容易地使用一个频道,though@EliasVanOotegem我不想让它们按顺序运行。这意味着阻塞和排队。我希望以后尝试运行goroutine时,能够意识到它已经在运行,不需要做任何事情,然后继续运行。谢谢。我认为这不能满足我的需要,因为
jobisrunning mu.Lock()
块位于
maybeStartJob()
。我不能阻止
maybeStartJob()
,因为它是事件驱动的,不完全在我的控制之下。这就是我遇到的问题,因为
sync
包中的几乎所有东西都是阻止调用。@ThunderCat如果你锁定了函数,你需要
jobsrunning
标志吗?这个例子似乎有点过于复杂了。这样的事情不足以确保作业的内容一次只由一个goroutine执行,同时也允许它由多个goroutine并发“排队”吗@Michael,你能看看上面评论中的链接吗?这能解决你的问题吗?@Michael maybeStartJob在查看标志时会屏蔽。这不太可能是应用程序中的问题。