I have a method which does a long action using an async task
Now, I want to add a cache mechanism that will be transparent in the same method.
Now, I could always fetch my cache result and wrap it with a Task so it will "work" but I want to prevent the context switch that I will get.
Here's an example of what I have:
var result = await LongTask();
private async Task<string> LongTask()
{
return await DoSomethingLong();
}
And here's an example of what I want:
var result = await LongTask();
private async Task<string> LongTask()
{
if(isInCache)
{
return cachedValue(); // cache value is a const string you can do return "1" instead.
}
// else do the long thing and return my Task<string>
return await DoSomethingLong();
}
Now I'm surprised to see that this compiled and worked
Something tells me that I'm not doing it correctly.
Here's another similar example that I've tested:
private async Task<string> DownloadString(bool sync)
{
using (WebClient wc = new WebClient())
{
var task = wc.DownloadStringTaskAsync("http://www.nba.com");
if(sync)
return task.Result;
return await task;
}
}
And here's the code:
var res = DownloadString(true);
string str1 = await res;
var res2 = DownloadString(false);
string str2 = await res2;
From what I've read here task.Result
executes the task synchronously and returns a string
.
Now I see the request via Fiddler and my program get's stuck on the return task.Result
line even though I see a 200 OK
and I wait a long time.
Bottom Line:
context switch overhead
?DownloadString
get stuck? Asynchronous caching simplifies the role of the application client in data caching and can significantly improve the performance of certain workloads. This post explains data caching behavior in Alluxio v1.
Three caching challenges to consider Caches take up space on the disk, so we have to assess whether the time we are saving is worth the amount of disk space used. Cached data might not be the most accurate, particularly for volatile real-time data. Therefore, volatile data should not be cached.
The first step is to add the async keyword to the method. It appears in the method signature in the same way that the static keyword does. Then, we need to wait for the download using the await keyword. In terms of C# syntax, await acts as a unary operator, like the !
Async functions always return a promise. If the return value of an async function is not explicitly a promise, it will be implicitly wrapped in a promise.
In-memory data lookup: If you have a mobile / web app front end you might want to cache some information like user profile, some historical / static data, or some api response according to your use cases. Caching will help in storing such data.
In computing, a cache is a high-speed data storage layer which stores a subset of data, typically transient in nature, so that future requests for that data are served up faster than is possible by accessing the data's primary storage location.
First of all, if after a call to an async
method the returned task is already completed there would be no context switch, because none is needed. So this is completely acceptable:
private async Task<string> LongTask()
{
if(isInCache)
{
return cachedValue(); // cache value is a const string you can do return "1" instead.
}
// else do the long thing and return my Task<string>
return await DoSomethingLong();
}
However, in the cases where the result is cached, the async
mechanism is redundant. This overhead is mostly negligible but you can improve performance by dropping both the async
and await
and create a completed task using Task.FromResult
:
private Task<string> LongTask()
{
if(isInCache)
{
return Task.FromResult(cachedValue());
}
// else do the long thing and return my Task<string>
return DoSomethingLong();
}
...when you write “await someObject;” the compiler will generate code that checks whether the operation represented by someObject has already completed. If it has, execution continues synchronously over the await point. If it hasn’t, the generated code will hook up a continuation delegate to the awaited object such that when the represented operation completes, that continuation delegate will be invoked
From Async/Await FAQ
Task.Result
doesn't execute the task synchronously, it waits synchronously. That means that the calling thread is blocked waiting for the task to complete. When you use that in an environment with a SynchronizationContext
that may lead to a deadlock since the thread is blocked and can't handle the task's completion. You shouldn't use the Result
property on a task that hasn't completed yet.
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