-
Notifications
You must be signed in to change notification settings - Fork 17.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
proposal: net/http: add Request.CopyTo #68501
Comments
Related Issues and Documentation
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.) |
You can copy the var sink *http.Request = new(http.Request)
func BenchmarkTest(b *testing.B) {
r := http.Request{}
for range b.N {
*sink = *r.WithContext(context.Background())
}
}
|
@mateusz834, thanks! That's an interesting optimization, but it seems like it depends heavily on the surrounding function and the compiler's ability to analyse the inlinability, so anyone reading should probably put that into a separate function: func CopyRequestTo(ctx context.Context, r *http.Request, clone *http.Request) {
*clone = *r.WithContext(ctx)
} |
@ainar-g If this gives real performance improvement we can always make sure that the |
The motivation for this proposal is performance. I think that the first step would be to demonstrate the real-world improvement from using this API. The HTTP server is pretty allocation heavy (and the representation of headers as a map makes allocations hard to avoid), and a middleware layer which is modifying an inbound request context is probably using context.WithValue which is also allocation-heavy. Does knocking off one allocation for a new Request make a practical difference? Microbenchmarks of Request.WithContext calls are going to be less interesting than an end-to-end test of the full serving path. |
@mateusz834, that would be good to have, although it also feels a bit magical. @neild, could you please provide a good example of measuring the full serving path, so that I could measure it? I may be misunderstanding what you're asking, but as far as I can see there is no way to benchmark something like an As for the real-world improvement, this issue has been motivated by some benchmarks I've made on a middleware covering a relatively high-load API area. |
Just as a side note the current issue with We also have an issue #62653, which proposes a way to reduce allocations caused by interfaces, maybe the compiler can be improved with a similar idea? escape-analysis could analyse every functions with the same signature across entire app, and see whether arguments escape, not ideal but it could remove allocations in case like this, where |
Make a small HTTP server serving a static response, including a middleware layer that (say) adds a context value to each request. Maybe look up the context value in the request handler, to be a bit more realistic. Then use something like wrk or hey to send some load to it and measure the max requests/second. |
Proposal Details
The Issue
Currently, the addition of new contexts to
net/http.Request
s always allocates. Even whennet/http.Request.WithContext
is used, which creates a shallow copy of the original request with the new context, there is still the allocation of a newRequest
value:This is a problem, since the pattern of taking the original context, creating a child context with additional data, and creating a copy of the original request with the new context is very common in HTTP middlewares.
Proposal
I propose adding a new method,
net/http.Request.CopyTo
:(The name is inspired by
github.com/miekg/dns.Msg.CopyTo
and is bikesheddable.)Request.WithContext
can thus be rewritten into:This allows HTTP middlewares to reuse
Request
structs by usingsync.Pool
s or some other mechanism to reuse the memory.Related
The text was updated successfully, but these errors were encountered: