Replace Task with ValueTask in frequently-called async methods that often complete synchronously.
Code Snippet
// Before: Always allocates a Task
public async Task GetCachedValueAsync(string key)
{
if (_cache.TryGetValue(key, out int value))
return value;
return await FetchFromDatabaseAsync(key);
}
// After: Zero allocation when cached
public ValueTask GetCachedValueAsync(string key)
{
if (_cache.TryGetValue(key, out int value))
return new ValueTask (value);
return new ValueTask (FetchFromDatabaseAsync(key));
}
Why This Helps
- Avoids Task allocation when result is immediately available
- Significant performance gain in cache-hit scenarios
- Backward compatible with existing async/await patterns
How to Test
- Benchmark with high cache-hit ratios
- Monitor allocation rate with dotMemory
When to Use
Caching layers, memoized computations, any async method with frequent synchronous completion.
Performance/Security Notes
ValueTask should only be awaited once. Don’t store or reuse ValueTask instances.
References
Try this tip in your next project and share your results in the comments!
Discover more from Byte Architect
Subscribe to get the latest posts sent to your email.