我们可以限制一次从goroutine一次调用函数吗

时间:2020-07-21 12:40:26

标签: go

我有以下情况

wg.Add(1)
go func(wg *sync.WaitGroup) {
    defer wg.Done()
    for {
        select {
            case <-tickerCR.C:
                _ = ProcessCommands()
            case <-ow.quitCR:
                logger.Debug("Stopping ProcessCommands goroutine")
                return
        }
    }
}(&wg)

我能以某种方式确保如果ProcessCommands正在执行,则忽略下一个股票报价事件。基本上我想避免并行执行ProcessCommands

4 个答案:

答案 0 :(得分:2)

您想要的东西称为互斥。可以通过Mutex来实现。

var m Mutex

func process() {
    m.Lock()
    defer m.Unlock()
    ProcessCommands()
}

答案 1 :(得分:1)

您可以创建一个具有两个字段的类型,一个函数和一个互斥锁,当调用他的类型时,可以说运行方法,它锁定,推迟解锁并调用存储的函数。之后,您只需要使用所需的功能创建该类型的实例。 OOP进行救援。请记住,函数可以以与字符串相同的方式存储在结构中。

import (
    "sync"
)

type ProtectedCaller struct {
    m sync.Mutex
    f func()
}

func (caller *ProtectedCaller) Call() {
    caller.m.Lock()
    defer caller.m.Unlock()
    caller.f()
}

func ProtectCall(f func()) ProtectedCaller {
    return ProtectedCaller{f: f}
}

var processCommands = ProtectCall(ProcessCommands)

答案 2 :(得分:0)

有一个半标准模块 x/sync/singleflight

使用方法:

import "golang.org/x/sync/singleflight"

var requestGroup singleflight.Group

// This handler should call it's upstream only once:

http.HandleFunc("/singleflight", func(w http.ResponseWriter, r *http.Request) {
        // define request group - each request can have it's specific ID
        // singleflight ensures only 1 request with any given ID is processed at a time
        // also you can have different IDs - to be processed simultaneously  
        // just set ID to "singleflight-1", "singleflight-2", etc
        res, err, shared := requestGroup.Do("singleflight", func() (interface{}, error) {
            fmt.Println("calling the endpoint")
            response, err := http.Get("https://jsonplaceholder.typicode.com/photos")

            if err != nil {
                http.Error(w, err.Error(), http.StatusInternalServerError)
                return nil, err
            }
            responseData, err := ioutil.ReadAll(response.Body)
            if err != nil {
                log.Fatal(err)
            }
            time.Sleep(2 * time.Second)
            return string(responseData), err
        })

        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }
        result := res.(string)
        fmt.Println("shared = ", shared)
        fmt.Fprintf(w, "%q", result)
    })

source

答案 3 :(得分:0)

您可以使用sync.Once并防止多次调用一个函数,如下所示:

wg.Add(1)
var once sync.Once
go func(wg *sync.WaitGroup) {
    defer wg.Done()
    for {
        select {
            case <-tickerCR.C:
                   // look at this line, "ProcessCommands" function will call only once
                   once.Do(ProcessCommands)
            case <-ow.quitCR:
                logger.Debug("Stopping ProcessCommands goroutine")
                return
        }
    }
}(&wg)