GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||||||
GeezerVison is showing github.com — Several improvements to SocketsHttpHandler perf by stephentoub · Pull Request #41640 · dotnet/corefx
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Conversation
Member
Fixes https://github.com/dotnet/corefx/issues/39835 Commit 1: Commit 2: Commit 3: Benchmark:
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Diagnosers; using BenchmarkDotNet.Running; using System; using System.Net; using System.Net.Http; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; [MemoryDiagnoser] public class Program { static void Main(string[] args) => BenchmarkSwitcher.FromTypes(new[] { typeof(Program) }).Run(args); private static Socket s_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); private static HttpClient s_client = new HttpClient(new HttpClientHandler() { ServerCertificateCustomValidationCallback = delegate { return true; } }); private static Uri s_uri; [Benchmark] public async Task HttpGet() { var m = new HttpRequestMessage(HttpMethod.Get, s_uri); m.Headers.TryAddWithoutValidation("Authorization", "ANYTHING SOMEKEY"); m.Headers.TryAddWithoutValidation("Referer", "http://someuri.com"); m.Headers.TryAddWithoutValidation("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36"); m.Headers.TryAddWithoutValidation("Host", "www.somehost.com"); (await s_client.SendAsync(m, default)).Dispose(); } [GlobalSetup] public void CreateSocketServer() { s_listener.Bind(new IPEndPoint(IPAddress.Loopback, 0)); s_listener.Listen(int.MaxValue); var ep = (IPEndPoint)s_listener.LocalEndPoint; s_uri = new Uri($"http://{ep.Address}:{ep.Port}/"); byte[] response = Encoding.UTF8.GetBytes("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); byte[] endSequence = new byte[] { (byte)'\r', (byte)'\n', (byte)'\r', (byte)'\n' }; Task.Run(async () => { while (true) { Socket s = await s_listener.AcceptAsync(); _ = Task.Run(() => { using (var ns = new NetworkStream(s, true)) { byte[] buffer = new byte[1024]; int totalRead = 0; while (true) { totalRead += ns.Read(buffer.AsSpan(totalRead)); if (buffer.AsSpan(0, totalRead).IndexOf(endSequence) == -1) { if (totalRead == buffer.Length) Array.Resize(ref buffer, buffer.Length * 2); continue; } ns.Write(response); totalRead = 0; } } }); } }); } }
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page. All reactions
When enumerating headers to write them out, do not force them to be parsed if the user explicitly asked for them not to be with "WithoutValidation". If the key/values are incorrectly formatted, the request may end up being written incorrectly on the wire, but that's up to the developer explicitly choosing it. Several releases ago, when we weren't paying attention to ExpectContinue, we optimized away the backing field for it into a lazily-initialized collection; that made it cheaper when not accessed but more expensive when accessed, which was fine, as we wouldn't access it from the implementation and developers would rarely set it. But now SocketsHttpHandler checks it on every request, which means we're paying for the more expensive thing always. So, revert the optimization for this field.
stephentoub
force-pushed
the
noforceparseheaders
branch
from
dfe8860 to
866931b
Compare
All reactions
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page.
|
There was an error while loading. Please reload this page.
|
Which style changes? Just the |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
I'm curious/hopeful if this change will help with #22638. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
When we enumerate the headers to write them out, we currently allocate a string[] for each. We can instead just fill the same array over and over and over.
866931b to
df25530
Compare
|
Re retrieving header values: It would be nice to avoid the string[] allocation here entirely. This is particularly relevant for HTTP3 since there's no easy way to reuse the string[] across requests -- each request is on its own QUIC stream. But I don't see an obvious way to do this. Maybe a callback model? We can defer that for now. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
/azp run |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Azure Pipelines successfully started running 4 pipeline(s). |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
* Do not force-parse TryAddWithoutValidation headers in SocketsHttpHandler When enumerating headers to write them out, do not force them to be parsed if the user explicitly asked for them not to be with "WithoutValidation". If the key/values are incorrectly formatted, the request may end up being written incorrectly on the wire, but that's up to the developer explicitly choosing it. * Revert HttpRequestHeaders.ExpectContinue optimization Several releases ago, when we weren't paying attention to ExpectContinue, we optimized away the backing field for it into a lazily-initialized collection; that made it cheaper when not accessed but more expensive when accessed, which was fine, as we wouldn't access it from the implementation and developers would rarely set it. But now SocketsHttpHandler checks it on every request, which means we're paying for the more expensive thing always. So, revert the optimization for this field. * Avoid allocating a string[] per header When we enumerate the headers to write them out, we currently allocate a string[] for each. We can instead just fill the same array over and over and over. Commit migrated from dotnet/corefx@4d346a9
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
HttpClient requests - improve header parsing perf (when TryAddWithoutValidation)
There was an error while loading. Please reload this page.