Project · Async

Bounded batch loader

Compose cancellable asynchronous work in small deterministic batches.

All C# source files below are loaded together in the playground. Files written by a run live in its virtual directory.

Program.cs

using System;
using System.Linq;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;

using var cancellation = new CancellationTokenSource();
var values = await BatchLoader.LoadAsync(new[] { 1, 2, 3, 4, 5 }, 2, cancellation.Token);
Console.WriteLine(string.Join(",", values));

Async/BatchLoader.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
public static class BatchLoader
{
    public static async Task<int[]> LoadAsync(IEnumerable<int> ids, int batchSize, CancellationToken token)
    {
        if (batchSize is < 1 or > 32) throw new ArgumentOutOfRangeException(nameof(batchSize));
        var results = new List<int>();
        foreach (var batch in ids.Chunk(batchSize))
        {
            token.ThrowIfCancellationRequested();
            results.AddRange(await Task.WhenAll(batch.Select(id => LoadOneAsync(id, token))));
        }
        return results.ToArray();
    }
    private static async Task<int> LoadOneAsync(int id, CancellationToken token)
    {
        await Task.Delay(1, token);
        return id * 10;
    }
}

Boundedbatchloader.csproj

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
</Project>