英文:
Go http.Client. Why the elapsed time is so big?
问题
我有一个类似这样的代码。简单来说,我正在创建一个带有超时的HTTP客户端,并向某些服务器发送一些请求。
package rtb
import (
"bytes"
"net/http"
"time"
)
var tcpHttpClient *http.Client
func init() {
tcpHttpClient = &http.Client{
Timeout: time.Millisecond * 200,
}
}
func doRequest(url string, reqBody []byte) {
req, err := http.NewRequest("POST", url, bytes.NewBuffer(reqBody))
if err != nil {
return
}
defer resp.Body.Close()
// 这一行返回一个错误
resp, clientError := tcpHttpClient.Do(req)
// ...
}
问题是,有时候经过的时间比超时时间要长得多。我无法理解为什么会这样。
例如:请求未成功,出现错误消息"上下文截止超时(等待标头时超过了Client.Timeout)"。客户端的超时时间为200毫秒,但经过的时间为3秒。据我所知,Client.Timeout应该覆盖从拨号到获取响应正文的整个过程。
那么,为什么经过的时间比超时时间长?为什么请求没有更早地被取消?
英文:
I have a code like this. To be short, I'm creating the http client with a timeout and doing some request to some server.
package rtb
import (
"bytes"
"net/http"
"time"
)
var tcpHttpClient *http.Client
func init() {
tcpHttpClient = &http.Client{
Timeout: time.Millisecond * 200,
}
}
func doRequest(url string, reqBody []byte) {
req, err := http.NewRequest("POST", url, bytes.NewBuffer(reqBody))
if err != nil {
return
}
defer resp.Body.Close()
// This line returns an error
resp, clientError := tcpHttpClient.Do(req)
// ...
}
The problem is, sometimes the elapsed time is a WAY lot bigger than the timeout itself. And I can't understand why.
Example: The request has not succeeded with the error message "context deadline exceeded (Client.Timeout exceeded while awaiting headers)".
The timeout of the client is 200ms, but the elapsed time is 3 seconds. As far as I know, the Client.Timeout should cover all the way from the dial to the getting the response body.
So, why the elapsed time is bigger than the timeout? Why the request has not been cancelled earlier?
答案1
得分: 2
简而言之,当计算机发出HTTP请求时,会发生很多事情。没有一个并行运行的计时器来不断检查超时并尽快取消HTTP请求。但在所有必要的步骤之间,会检查是否超过了超时时间。当超时时间超过时,系统开始取消请求并执行其他清理任务。在您的情况下,第一个检查到超时时间已过的检查发生在三秒钟之后。
因此,直到返回错误的时间可能比指定的超时时间要长得多,但给定的限制是受到尊重的。
顺便提一下:当进行许多不受您控制的异步任务(例如通过网络进行HTTP请求)时,可以使用Go协程来解除主协程的阻塞。
英文:
In a nutshell and very simplified: There is a lot happening when a computer makes an HTTP request. There is no timer running in parallel that constantly checks the timeout and cancels the HTTP request as soon as possible. But between all necessary steps there is a check if the timeout is exceeded. When the timeout is exceeded, the system starts to cancel the request and does other cleanup tasks. In your case the first check that noticed that the timeout was exceeded happened after three seconds.
So it might take much longer than the specified timeout until the error is returned, but the given limit is respected.
As a side note: When making a lot of asynchronous tasks that are out of your control (like doing an HTTP request over a network) go routines can be used to unblock your main routine.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论