Skip to content

alanmcgovern/ReusableTasks

Repository files navigation

ReusableTask

NuGet version Build status

A .NET Standard 2.0 compatible library which can be used to implement zero allocation async/await. This is conceptually similar to ValueTask<T>, except it's compatible with .NET 2.0 and has zero ongoing allocations once the internal cache initializes.

Sample usage:

public async ReusableTask InitializeAsync ()
{
    if (!Initialized) {
        await LongInitializationAsync ();
        Initialized = true;
    }
}

async ReusableTask LongInitializationAsync ()
{
    // Contact a database, load from a file, etc
}

public async ReusableTask<MyData> CreateMyDataAsync ()
{
    if (!Initialized) {
        mydata = await LongMyDataCreationAsync ();
        Initialized = true;
    }
    return mydata;
}

async ReusableTask<MyData> LongMyDataCreationAsync ()
{
    // Contact a database, load from a file, etc..
    return new MyData (....);
}

The compiler generated async state machine for these methods is allocation-free, and results in no garbage collectable objects being created no matter how many times the methods are invoked.

The four things you cannot do with ValueTask you also cannot do with ReusableTask. The documentation can be read here in the remarks section, https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.valuetask-1?view=netcore-3.0#remarks.

Unlike the documentation states for ValueTask, I would recommend that the default return value for any async method should be ReusableTask or ReusableTask<T>, unless benchmarking shows otherwise.