using System.Threading.Tasks;
public static class Program
await TestAsync("Using Task<object>", true, TaskLoop);
await TestAsync("Using ValueTask<object>", true, ValueTaskLoop);
await TestAsync("Using Task<object>", false, TaskLoop);
await TestAsync("Using ValueTask<object>", false, ValueTaskLoop);
static async Task TestAsync(string title, bool asynchronous,
Func<bool, CancellationToken, Task<int>> loop)
long mem0 = GC.GetTotalAllocatedBytes(true);
var cts = new CancellationTokenSource(1000);
int count = await loop(asynchronous, cts.Token);
long mem1 = GC.GetTotalAllocatedBytes(true);
Console.WriteLine($"{title} - " +
(asynchronous ? "Asynchronous" : "Synchronous") + " completion");
Console.WriteLine($"- Loops: {count:#,0}");
Console.WriteLine($"- Allocations: {mem1 - mem0:#,0} bytes");
double perLoop = (mem1 - mem0) / (double)count;
Console.WriteLine($"- Allocations per loop: {perLoop:#,0} bytes");
static async Task<object> TaskOne(bool asynchronous)
if (asynchronous) await Task.Yield();
static async ValueTask<object> ValueTaskOne(bool asynchronous)
if (asynchronous) await Task.Yield();
static async Task<int> TaskLoop(bool asynchronous, CancellationToken token)
while (!token.IsCancellationRequested)
var result = await TaskOne(asynchronous);
if (result == null) break;
static async Task<int> ValueTaskLoop(bool asynchronous, CancellationToken token)
while (!token.IsCancellationRequested)
var result = await ValueTaskOne(asynchronous);
if (result == null) break;