IO performance improvements
Pre-releaseIn one of the proposals leading up to the big v5
refactor, I discussed the idea of using SpinWait
as a lightweight waiting technique to avoid the use of the async/await machinery everywhere. I also mentioned that the idea might be too primitive. Well, it was.
So, I have modified the internals of the IO
monad (which is where all async code lives now) to have four possible states: IOSync
, IOAsync
, IOPure
, and IOFail
. These are just types derived from IO
(you never see them).
The idea is that any actual asynchronous IO will just use the regular async/await machinery (internally in IOAsync
), any synchronous IO will be free of async/await (in IOSync
), and any pure or failure values will have a super simplified implementation that has no laziness at all and just can pre-compute.
The TestBed.Web
sample with the TestBed.Web.Runner
NBomber test now runs both the sync
and async
versions with exactly the same performance and with no thread starvation; and without any special need to fork the IO operation on the sync
version.
I consider that a big win which will allow users to avoid async/await entirely (if they so wish), one of the goals of 'Drop all Async variants' proposal.
app.MapGet("/sync",
() => {
var effect = liftIO(async () =>
{
await Task.Delay(1000);
return "Hello, World";
});
return effect.Run();
});
app.MapGet("/async",
async () => {
var effect = liftIO(async () =>
{
await Task.Delay(1000);
return "Hello, World";
});
return await effect.RunAsync();
});