Assume i have the following interface:
public interface IApiOutputCache
{
Task RemoveStartsWithAsync(string key);
Task<T> Get<T>(string key) where T : class;
Task RemoveAsync(string key);
Task<bool> ContainsAsync(string key);
Task Add(string key, object o, DateTimeOffset expiration, params string[] dependsOnKeys);
Task<IEnumerable<string>> GetAllKeys();
}
I can implement different cache providers. I implemented it twice for two different caches:
a) azure redis b) memory cache
For azure redis this works absolutely fine since StackExchange.Redis offers all the async methods for me so i can stay completely async.
Now i implement another one for the memory cache which does not offer async api for me.
Now what is the best pratice to implement this interface?
Implement it as is but just do everything sync? Warp the internal calls to a Task.Run
(not a good idea for fast mem cache calls i think).
The async keyword does not make code synchronous. async/await is just a tool to make the syntax for interacting with promises nicer. It's still using promises. "node is asynchronous (meaning multiple lines of code execute at the same time)" that is not what asynchronous means.
In my discussion of “async over sync,” I strongly suggested that if you have an API which internally is implemented synchronously, you should not expose an asynchronous counterpart that simply wraps the synchronous method in Task. Run.
Use the Result property on the asynchronous Task, like so: // Synchronous method. void Method()
Interfaces can't use async in a method declaration, simply because there is no need. If an interface requires that a method returns Task , the implementation may choose to use async , but whether it does or not is a choice for the implementing method.
Forget about Task.Run
, there's no need to offload anything to the ThreadPool
.
Implement everything synchronously and return an already completed Task
with Task.FromResult
when returning a value and Task.CompletedTask
when not:
Task<T> GetAsync<T>(string key)
{
T result = Get(key);
return Task.FromResult(result);
}
Task RemoveAsync(string key)
{
Remove(key);
return Task.CompletedTask;
}
Or even better, since it's a cache you can cache the tasks themselves instead of the results and return the same task object every time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With