A non-reentrant function is a function that can only be executed once at any point in time, regardless of how many times it is called and how many goroutines there are.
A certain service polls certain conditions and monitors some status every second. We want each state to be checked independently without blocking.
Implementation may be like this: (Recommended Learning: Go )
func main() { tick := time.Tick(time.Second) go func() { for range tick { go CheckSomeStatus() go CheckAnotherStatus() } }() }
We choose to run every in our goroutine Status check so that CheckAnotherStatus() does not wait for CheckSomeStatus() to complete.
Each check usually takes a short time, much less than a second. But what happens if CheckAnotherStatus() itself takes more than a second to run? There may be an unexpected network or disk delay that affects the check execution time.
Does it make sense to execute a function twice at the same time? If not, we want it to be non-reentrant.
Blocking, non-reentrant functions
An easy way to prevent a function from running multiple times is to use sync.Mutex.
Assuming we only care about calling this function from the above loop, we can implement the lock from outside the function:
import ( "sync" "time" ) func main() { tick := time.Tick(time.Second) var mu sync.Mutex go func() { for range tick { go CheckSomeStatus() go func() { mu.Lock() defer mu.Unlock() CheckAnotherStatus() }() } }() }
The above code guarantees CheckAnotherStatus() Not performed by multiple iterations of the loop. When CheckAnotherStatus() was previously executed, any subsequent iterations of the loop would be blocked by the mutex.
The blocking solution has the following properties:
It ensures that there are as many calls to "CheckAnotherStatus()" as the number of loop iterations.
Assuming a stall executing "CheckAnotherStatus()", subsequent iterations result in requests to call the same function.
Yield, non-reentrant function
It probably doesn't make sense to stack up for the next 10 calls in our status check story. A stalled CheckAnotherStatus() execution completes, all 10 calls suddenly execute, sequentially, and may be completed within the next second, with 10 identical checks completed in the same second.
Another solution is to surrender. A profitable solution is:
Abort execution of "CheckAnotherStatus()" if it has already been executed.
The execution of "CheckAnotherStatus()" will be run at most once.
Fewer calls to "CheckAnotherStatus()" may actually be run compared to the number of loop iterations.
The above is the detailed content of Golang non-reentrant function implementation. For more information, please follow other related articles on the PHP Chinese website!