惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
Microsoft Security Blog
Microsoft Security Blog
Recent Announcements
Recent Announcements
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Last Week in AI
Last Week in AI
罗磊的独立博客
腾讯CDC
云风的 BLOG
云风的 BLOG
月光博客
月光博客
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 三生石上(FineUI控件)
宝玉的分享
宝玉的分享
U
Unit 42
I
InfoQ
D
DataBreaches.Net
Blog — PlanetScale
Blog — PlanetScale
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
V2EX
美团技术团队
IT之家
IT之家
Stack Overflow Blog
Stack Overflow Blog
F
Fortinet All Blogs
GbyAI
GbyAI
S
SegmentFault 最新的问题

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
The People v. ASP.NET Core: A C#-Only HTTP Benchmark Trial
Benny · 2026-06-26 · via DEV Community

All rise. The Honorable HttpArena presiding.

Today's docket is exclusively C# versus C#. No Rust defendants smirking from the gallery, no Go gophers passing notes. Just .NET frameworks, their press releases, and a 64-core AMD Threadripper PRO 3995WX that does not care about your README. Every entry was run through 27 scored profiles in an identical Dockerized harness — server pinned to one half of the chip, the gcannon load generator pinned to the symmetric other half, so the prosecution literally cannot steal cycles from the witness.

The court's motto, etched above the bench: "Don't just say you're fast, prove it."

Before any number is admitted into evidence, the defendant must pass an 18-point validation suite with randomized anti-cheat probes — random query sums, two different random POST bodies (to catch response caching), empty-range DB queries that must return zero rows, and a TCP fragmentation test that splits the request across multiple writes with 30ms pauses. You cannot hardcode your way to an acquittal. Correctness is a precondition for a score.

Let's hear the cases.

Count One: GenHTTP v. ASP.NET Core, the headline rivalry

The prosecution alleges that GenHTTP — a community project by Kaliumhexacyanoferrat — claims to outrun Microsoft's flagship. Bold. The kind of claim that usually gets a framework held in contempt.

Except the evidence holds up. Taking the best variant of each camp per profile, the tally is GenHTTP 14, ASP.NET 4.

Exhibit A: the CRUD podium. A clean C# sweep, top to bottom, in requests per second:

Rank Framework RPS
1 genhttp-11 518,433
2 genhttp 464,774
3 genhttp-kestrel 452,652
4 simplew 430,132
5 simplew-tuned 417,396
6 aspnet-minimal 396,825
7 aspnet-iouring 357,713

The defense for Microsoft objects: "Minimal API is production-hardened, Your Honor." Sustained, and irrelevant. On this count, genhttp-11 beat aspnet-minimal by 1.31x.

The court asks: how? The answer is architectural, not magical. GenHTTP is a server and a framework in one library — your app is a tree of composable handler modules, not middleware on someone else's pipeline. On genhttp-11's native HTTP/1.1 engine, a request goes from a tight 1.1 parser straight into a precompiled handler tree with no ASP.NET middleware chain in the way. When the work per request is trivial — a baseline sum, a small JSON body — framework overhead dominates, and the leaner server wins.

// Wired once at startup, not per request:
Layout.Create()
    .Add("pipeline", Content.From(Resource.FromString("ok")))
    .AddService<Baseline>("baseline11")
    .AddService<Json>("json")
    .AddStaticFiles()
    .AddWebsocket();

The allocation discipline is admitted into the record too: ArrayPool<byte>.Shared for the 16KB upload buffer, Websocket.Imperative().DoNotAllocateFrameData() for zero-copy echo frames, server GC, and an Npgsql multiplexing pool. This is not a framework that says it's careful. The bytes don't lie.

The full spread of GenHTTP's 14 wins, for the record: baseline 1.20x (2,075,459 vs 1,733,724), pipelined 1.40x (17,885,664 vs 12,807,538), limited-conn a brutal 2.24x, json 1.38x, json-comp 1.28x, json-tls 1.30x, upload 1.91x, static 1.47x, crud 1.31x, api-4 1.11x, api-16 1.29x, echo-ws 1.26x, and echo-ws-pipeline 1.45x (28.6M vs 19.7M frames). The fourteenth is baseline-h3 at 1.02x — the framework equivalent of winning an argument by a single word and then refusing to make eye contact. On plaintext HTTP/1.1 and WebSockets, the verdict is not close.

Count Two: ASP.NET's airtight alibi

Now the defense gets its moment, and it's a strong one. ASP.NET's 4 wins span HTTP/2 (baseline-h2, static-h2), HTTP/3 (static-h3), and async-db.

Profile Winner Margin
baseline-h2 aspnet-minimal 1.48x (2,648,217 vs 1,792,309)
static-h2 aspnet-minimal 2.33x (375,583 vs 161,502)
static-h3 aspnet-minimal 1.20x
async-db aspnet-minimal 1.15x (225,491 vs 196,599)

Here's the twist the jury needs to understand: GenHTTP's native engine is HTTP/1.1-only. No HPACK, no stream multiplexing, no QUIC. So for HTTP/2 and HTTP/3, GenHTTP must borrow Kestrel — the genhttp-kestrel variant ships libmsquic and binds 8443 over TCP and UDP. And once both sides are standing on Kestrel, Microsoft's years-hardened h2 stack — tuned here to 256 streams per connection, a 2MB connection window, 1MB stream windows — wins decisively. The 2.33x static-h2 margin isn't an upset. It's the incumbent defending its own courthouse.

That "Kestrel owns h2" story covers exactly two of these rows — baseline-h2 and static-h2. The other two wins are different animals. async-db is a database-bound profile; that one rides Npgsql and async query handling, not the maturity of an h2 stack. And static-h3 is HTTP/3 — where ASP.NET does not sweep, because GenHTTP took baseline-h3 by 1.02x. Call QUIC a split decision, not a shutout.

Engine/handler separation is the whole trick, and it cuts both ways: the same handler tree drops onto GenHTTP's engine or onto Kestrel unchanged. GenHTTP wins where its lean engine runs; it concedes where it has to rent Microsoft's.

Count Three: the witness who built their own runtime

aspnet-minimal-iouring takes the stand wearing the most elaborate alibi in the building. To swap Kestrel's socket transport from epoll to io_uring, it ships a hand-built fork of the .NET runtime (Ben Adams' branch, dotnet/runtime#124374) via a 3-stage Docker build that clones, patches socket internals with a Python script, and overlays System.Net.Sockets.dll onto the stock framework.

That's not a fighter, that's a fighter who reforged his own gloves in the locker room. The patch exists because the branch wouldn't even compile — it had to rewrite a &result taken on an out int param and clamp io_uring's 128-byte accept sockaddr into a family-sized buffer. The court admires the dedication. It also notes that io_uring with SQPOLL pays off on cheap pipelined h1, not CPU-bound h2/TLS — and on CRUD it landed 7th. Effort is not throughput.

Count Four: the marketing department, on trial

Some claims did not survive cross-examination.

ServiceStack, the "one framework to power them all," posted 22,976 RPS on json-4096 (dead last) and 14,268 on pipelined-512 (also dead last). The prosecution produces CPU traces: ~700–1700% utilization on a 64-core box. That is not a framework saturating its cores. That is the enterprise tax showing up on a Tuesday — a full DTO pipeline on Kestrel plus a global response-compression middleware that taxes even the plaintext ok route. Guilty of layering.

aspnet-mvc is its co-defendant. The same handlers that fly under Minimal API get bogged down behind controller dispatch, model binding, filters, content negotiation, and reflection-based JSON of anonymous objects on every single request. Minimal APIs compile each MapGet into a near-direct RequestDelegate; MVC pays the family's catering bill, request after request.

aspnet-minimal-aot pleads efficiency. True — Native AOT strips the JIT and reflection surface and wins on cold start. But under cross it concedes ~900MiB–1GiB working set, because ServerGC reserves the heap regardless. Footprint is a heap problem, not a JIT problem.

simplew-tuned is the most honest witness in the room: the entire speedup over plain simplew is four socket flags — TcpNoDelay, ReuseAddress, TcpKeepAlive, ReusePort — plus a compressed static-file cache. Same application code. No perjury, just config.

A note on the geomean defendants

The court must address an attempted mistrial. A naive geomean composite shows dogrider — the arena owner's own zerg io_uring WebSocket echo server — and fleck sitting on top. Objection sustained: they ran only 2 WebSocket profiles each. The naive composite is a geometric mean taken only over the profiles an entry actually ran — so a two-profile WebSocket specialist with monster echo numbers floats to the top on a sample size of two. The fix a fair ranking needs is coverage-weighting: average across all 27 profiles, zero-filling the ones an entry skipped. Do that and the two-trick acts sink, because every ducked profile becomes a zero dragging the mean down — which is exactly the point. A framework covering 24 profiles at 80% beats a specialist who only showed up twice. Even the platform owner's entry doesn't get to skip the work and keep the crown.

So the real findings of fact:

  • Most complete all-rounder: aspnet-minimal, 24 profiles.
  • Broadest performance leader: genhttp-11, 14 head-to-head wins.

The verdict

On plaintext, pipelining, uploads, static files, CRUD, and WebSockets, the community challenger genhttp-11 outperforms Microsoft's flagship. On HTTP/2 — and on a database-bound async route — ASP.NET Core's mature stack wins so cleanly that on h2 GenHTTP shows up borrowing it; HTTP/3 splits down the middle. Both headline claims — "the lean engine is faster" and "Kestrel owns h2" — are, on this evidence, true.

This is one published round: a snapshot, not a statute. Re-check the leaderboard, audit the raw load-generator logs, and if your C# framework thinks it can take the stand — add it. The harness is open, the same Threadripper awaits, and ./scripts/validate.sh is the bailiff. Bring a dish to the cookout. Just, you know, prove it's good first.

Court is adjourned. See the full evidence at http-arena.com.