Redakt was built from the ground up using the asynchronous programming model. All methods that may execute asynchronously have an Async method name suffix (e.g. SaveAndPublishAsync). For Redakt, these are almost all I/O bound async methods.

ValueTask

For many methods, the result may be returned either asynchronously or synchronously. This is not always known in advance. As Redakt uses caching aggressively, in practice, most service method calls will return their results from cache. Depending on your cache settings and website traffic, cache hits can (and should) go to the high 90% range. When using the default in-memory cache, cache hits will all be synchronous method returns.

The actual percentage of synchronous results vs. asynchronous results depends largely on your configuration and website traffic. For example, when using a Redis cache, all cache hits will be asynchronous as well.

When most of the time code is actually running synchronously, Task-based programming has significant overhead in memory consumption and garbage collection. C# 7 introduced generalized async return types and the ValueTask<T> struct, which does not allocate a Task object when the call completes synchronously, eliminating the extra overhead. Redakt uses the ValueTask<T> struct throughout the codebase.

In this article