1. Introduction
This article will introduce why timeout control is needed, and then introduce in detail the methods to implement timeout control in Go. Among them, we will discusstime
Package andcontext
The specific way of implementing timeout control for the package is to explain the applicable scenarios of both so that timeout control can be implemented in a more appropriate way in the program and improve the stability and reliability of the program.
2. Why timeout control is needed
Timeout control refers to the fact that when performing network requests or coroutine execution, in order to avoid the program waiting and causing resource waste, we need to set a timeout time for these operations. If the operation is not completed within the specified time, we need to stop waiting or terminate the operation.
For example, when making a network request, if a problem occurs on the server side, resulting in no timely response, the client may wait for the server to respond, which will cause waste of client resources.
To give a simple example, for example, we need to obtain a resource from a remote server, we can use the following code to implement it:
func getResource() (Resource, error) { conn, err := ("tcp", ":8888") if err != nil { return nil, err } defer () // Send a request and wait for a response _, err = ([]byte("GET /resource HTTP/1.1\r\nHost: \r\n\r\n")) if err != nil { return nil, err } resp, err := (conn) if err != nil { return nil, err } // parse the response and return the resource return parseResource(resp) }
But if the remote server does not respond after we send the request, then our program will wait and cannot continue to perform other tasks.
In some cases, this may cause blockage of the program, which affects the performance and stability of the program. Therefore, when performing network communication and other operations, especially when calling external APIs or accessing remote servers, timeout control must be used. Then, inGo
In the language, what are the implementation methods of timeout control?
3. Methods of timeout control
3.1 Time package implements timeout control
time
Packages provide multiple ways to implement timeout control, includingfunction,
Functions and
Functions, using them can implement timeout control, below
As an example, how to use it
time
Package implements timeout control. The code example is as follows:
// Create a timertimer := (5 * ) defer () // Use a channel to listen for whether the task has been completedch := make(chan string, 1) go func() { // Simulate the task and sleep for 5 seconds (2* ) ch <- "hello world" }() // Wait for the result through the select statement, the task returns normallyselect { case <-ch: ("Task completed normally") // ch has received the value, and the normal processing logic is usedcase <-: ("Timed out") // Timeout, go timeout logic}
In this example, we useMethod creates a timer with a timeout of 2 seconds. Then in
select
Used in a statement to wait for the result, and use which one returns first.
If the operation is completed within 2 seconds, the task is completed normally; if the operation is not completed after more than 2 seconds, thenselect
In the statement<-
The value will be received and the timeout processing logic will be passed.
3.2 context implements timeout control
Context
Interfaces are a context management mechanism provided in the Go language standard library. It allows the transfer of context information between different parts of the program, and can use it to implement functions such as timeout control, cancel operations, and truncation operations. in,Context
An interface existstimerCtx
The implementation of the , which can set a timeout time, after the timeout time is reached,timerCtx
The done channel of the object will be closed.
When it is necessary to determine whether the timeout is timed out, just callcontext
The object'sDone
method, it will returntimerCtx
The done channel in the object. If there is data returned, it means that the timeout has been timed out. Based on this, we can implement timeout control. The code example is as follows:
// Create a timerCtx and set the timeout to 3 secondsctx, cancel := ((), 3*) // Call the cancel function to free the occupied resourcesdefer cancel() // Use a channel to listen for whether the task has been completedch := make(chan string, 1) go func() { // Simulate the task and sleep for 5 seconds (2* ) ch <- "hello world" }() // Wait for the result through the select statement, the task returns normallyselect { case <-(): ("timeout") case result := <-ch: (result) }
Passed hereCreate a
timerCtx
, set the timeout time, the timeout time is 3s. Then start a coroutine to execute the specific business logic.
Afterwardsselect
Statement, righttimerCtx
Listen at the same time as the business execution result. When the task processing timeouts, the timeout logic is executed; if the task completes before the timeout, the normal processing flow is executed. In this way, the timeout processing of the request is realized.
4. Applicable scenario analysis
As can be seen from the above,time
andtimerCtx
Both can be used to implement timeout control, but in fact, the applicable scenarios of the two are actually different. In some scenarios, timeout control is not suitable for usetime
to implement, but to usetimerCtx
It is more appropriate to achieve it. In some scenarios, both implementation methods are possible.
Below I will briefly introduce several common scenarios and then analyze them so that they can be implemented appropriately in the appropriate scenario.
4.1 Simple timeout control
For example, suppose we need to obtain some data from a remote service, we can use the http package in the Go standard library to make network requests. The general request function is as follows:
func makeRequest(url string) (string, error) { // Request data}
In order to avoid the long response time of the request, which causes the program to be in a waiting state for a long time, we need to implement timeout processing for this function to ensure that the program can respond to other requests in a timely manner, rather than waiting all the time.
To achieve this, you can use ittime
Pack ortimerCtx
to implement timeout control. existmakeRequest
Timeout control is implemented in the function, the code here shows theMethods for timeout control of third pointThe code examples in it are roughly the same, just need to put the coroutinesleep
Just switch the function to specific business logic, and I won't go into details here. Moreover, looking at the above code example, we can also seetimer
ortimerCtx
In this scenario, the difference is not big, and it can be replaced by each other at this time.
Therefore, for such scenarios that control the execution time of a certain function, you can choose anytime
ortimerCtx
One of them is achieved.
4.2 Optional timeout control
Here we implement a method to establish a network connection. When the user calls this method, he passes in the list of addresses to be established. Then the method traverses the incoming address list and attempts to connect to each address until the connection is successful or all addresses are attempted to complete. The function definition is as follows:
func dialSerial(ras addrList) (Conn, error){ // Execute the logic to establish a network connection}
Based on this, an optional timeout control function is implemented based on this function. If the user calls this method and has a specified timeout time, the timeout control will be performed at this time; if the timeout time is not specified, the timeout control will not be performed at this time. Used here separatelytime
Package andcontext
accomplish.
First of all,time
The package implements optional timeout control, and can implement optional timeout control by passing the timer through the function parameter. Specifically, the timer may be used as aParameters of type are passed to the function and then used in the function
select
monitorIt is timeout; if no timer instance is passed, the timeout control will not be performed by default. The code implementation is as follows:
func dialSerial(timeout , ras addrList) (Conn, error){ // Execute the logic of establishing a network connection. When trying to establish a connection for each address, first check whether the timeout is reached. for i, ra := range ras { // Use this to perform timeout control, first determine whether the timer instance is passed to if timeout != nil { select { // Whether the listening timeout case <-: return nil, ("timeout") default: } } // Execute the logic to establish a network connection later } }
Then usetimerCtx
To implement the implementation of timeout control, you can pass a functionInterface parameters to implement timeout control.
Specifically, the user can pass aThe interface implementation, if there is a specified timeout time, pass in one
timerCtx
Implementation; if timeout control is not required, it can be transmitted in, it will never time out. Then the function is called
Done
Method to determine whether the timeout is exceeded, thereby realizing timeout control. The code implementation is as follows:
func dialSerial(ctx , ras addrList) (Conn, error){ // Execute the logic of establishing a network connection. When trying to establish a connection for each address, first check whether the timeout is reached. for i, ra := range ras { select { case <-(): return nil, &OpError{Op: "dial", Net: , Source: , Addr: ra, Err: mapErr(())} default: } // Execute the logic to establish a network connection } }
View the above code,dialSerial
The function implements optional timeout control, it seems that the incoming parameters are different, one is the incoming timerExample, one is passed in
Interface instances, but in fact it's not just that.
First of all, the readability of the code is passed inInstance to implement timeout control, not
Go
The common implementation methods in the user are difficult to understand; and forInterfaces are widely used. If you want to implement timeout control, the user only needs to pass in one.
timerCtx
The example is just for users, and the code is more readable.
Secondly, for the wholeGo
In terms of language ecology,Interfaces are widely used in the Go language standard library, and are generally timeout controls are used.
timerCtx
To achieve, if aThe example is actually with the whole
Go
The language timeout control is out of place. AbovedialSerial
As an example, the method needs to establish a network connection to call the underlying function to assist in the implementation, such as:
func (fd *netFD) connect(ctx , la, ra ) (rsa , ret error) { // Execute the logic to establish the connection switch err := connectFunc(, ra); err { // No error is reported, check whether the timeout is timed out at this time case nil, : select { case <-(): // If the timeout has been completed, the timeout error will be returned at this time return nil, mapErr(()) default: } } }
And just so happens that this function also implements optional timeout control, and it istimerCtx
To achieve, if it is passed in at this timetimerCtx
The timeout has been reached, and the function will directly return a timeout error.
If abovedialSerial
The timeout control is throughIf you implement the interface instance, when calling the function, the external
Context
The instance is passed as a parameterconnect
For functions, outer calls do not need to check whether the function timed out, and the code is more reusable.
Relatively, ifdialSerial
The timeout control is implemented through incoming timers, and it cannot be used well at this time.connect
The method has implemented the mechanism for timeout checking.
Therefore, in summary, useThe interface is an optional timeout control parameter, compared to using
, more suitable and more efficient, with the whole
Go
Language implementation can also be better integrated.
Summarize
Context
andTime
They are all methods to implement timeout control in Go language. They each have their own advantages and disadvantages. It cannot be said which implementation is better. It is necessary to choose which method to use according to the specific scenario.
In some simple scenarios,Time
Package implementation timeout control may be more convenient because its API is simpler and only requires use()
Functions can implement timeout control.
However, if multiple functions are involved, or multiple functions are requiredgoroutine
If you pass between them, use it at this timeContext
To implement timeout control may be more suitable.
5. Summary
This article introduces the reasons why timeout control is needed, mainly to avoid indefinite waiting, prevent resource leakage and improve program response speed.
Then we introduceGo
Methods to implement timeout control in the language, including usingtime
Implement timeout control and usecontext
Implement timeout control and give a simple code example.
Next, we analyze the applicable scenarios of these two implementations and clarify which scenarios are suitable for usetime
Implement timeout control and in which scenarios to usetimerCtx
to achieve more efficient.
Based on this, the introduction to why timeout control is needed has been completed. I hope that everyone can better implement it in scenarios where timeout control is needed.
The above is a detailed content to understand why Golang needs timeout control. For more information about Golang timeout control, please follow my other related articles!