Function function
Go functions do not support nesting, overloading and default parameters
But the following features are supported:
- No need to declare prototypes
- Indefinite length variable parameters
- Multiple return values
- Name the return value parameter
- Anonymous functions
- Closure
Preface
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.
This article explains blocking non-reentrant functions and producing non-reentrant functions in golang.
Scenario use cases
A service polls certain conditions and monitors some states every second. We want each state to be checked independently without blocking. The implementation might look like this:
func main() { tick := () go func() { for range tick { go CheckSomeStatus() go CheckAnotherStatus() } }() }
We choose to run each status check in our own goroutine so thatCheckAnotherStatus()
Will not waitCheckSomeStatus()
Finish.
Each check usually takes a short time and is much less than a second. But, if CheckAnotherStatus()
What happens if it takes more than one second to run? There may be an unexpected network or disk delay affecting the execution time of the check.
Does it make sense to execute a function twice at the same time? If not, we hope it is not reentrant.
Blocking, no reentering function
The simple way to prevent functions from running multiple times is to use。
Assuming we only care about calling this function from the loop above, we can implement the lock from outside the function:
import ( "sync" "time" ) func main() { tick := () var mu go func() { for range tick { go CheckSomeStatus() go func() { () defer () CheckAnotherStatus() }() } }() }
The above code guaranteesCheckAnotherStatus()
Not performed by multiple iterations of the loop. Execute beforeCheckAnotherStatus()
At the same time, any subsequent iteration of the loop will be blocked by a mutex.
A blocking solution has the following properties:
- It ensures many
CheckAnotherStatus()
” is called as the number of times iterations of the loop. - Assume that an execution "
CheckAnotherStatus()
” pause, subsequent iterations will cause requests to call the same function.
Submission, non-reenter function
In our status check story, it may not make sense to stack up for the next 10 calls. A stagnant CheckAnotherStatus()
Execution is complete, all 10 calls are executed suddenly, sequentially, and may be completed within the next second, with 10 same checks done in the same second.
Another solution is to surrender. A profitable solution is:
- If it has been executed
CheckAnotherStatus()
” aborted execution. - Will run at most once
CheckAnotherStatus()
” execution. - Compared to the number of cycle iterations, it is actually possible to run "
CheckAnotherStatus()
” has fewer calls.
The solution is implemented in the following ways:
import ( "sync/atomic" "time" ) func main() { tick := () var reentranceFlag int64 go func() { for range tick { go CheckSomeStatus() go func() { if atomic.CompareAndSwapInt64(&reentranceFlag, 0, 1) { defer atomic.StoreInt64(&reentranceFlag, 0) } else { return } CheckAnotherStatus() }() } }() }
atomic.compareandswapint64(&reentranceFlag, 0, 1)
Only inreentranceFlag==0
true will be returned and set to 1 atomically. In this case, entry is allowed and the function can be executed. reentranceFlag remains at 1 untilCheckAnotherStatus()
Finished, at which point it is reset. when CompareAndSwapInt64(...)
When false is returned, this meansreentranceFlag!=0
, which means that the function has been executed by another goroutine. The code generates and silently exits the function.
Summarize
We choose to implement non-reentrant code outside the function of the problem; we can implement it in the function itself. In addition, for int64, int32 is of course sufficient. The above is the content of this article. If you have any questions, please leave a message below the article to communicate.
Okay, the above is the entire content of this article. I hope that the content of this article has a certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support.