Как запустить один экземпляр горутина - PullRequest
0 голосов
/ 13 октября 2018

У меня есть программа, которая будет выполняться несколько раз.Но он может работать только по одному за раз (один экземпляр).Какой правильный / идиоматический способ убедиться, что определенная программа может запускаться только по одному за раз?

Вот мой придуманный пример кода, иллюстрирующий эту точку:

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
}

1 Ответ

0 голосов
/ 13 октября 2018

Исходя из вопроса и других комментариев ОП, похоже, что цель состоит в том, чтобы начать новую работу, если и только если она еще не запущена.

Использовать логическую переменную, защищенную 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 предупреждает, что функции в пакете требуют большой осторожности для правильного использования и что большинство приложений должны использовать пакет синхронизации.

...