I have web application which calls an external API for data.
If a user triggers this external call, and the call is already in effect, I don't want a second request to trigger a new call, but instead wait for the result of the first call (the result of the call will be the same for both requests).
How can I achieve this in c# using async/ await?
subsequent calls return existing task
Sure, you can do that just by keeping the Task<T> object and then returning it.
Something like:
private async Task<T> ImplementationAsync();
private Task<T> _task;
public Task<T> InterfaceAsync()
{
if (_task == null)
_task = ImplementationAsync();
return _task;
}
This is an extremely simple example. Real-world code should consider:
Can InterfaceAsync be called from multiple threads? If so, then _task needs to be protected.
Is this code loading a resource only one time? If so, then consider using AsyncLazy<T> instead of Task<T>.
Should this code re-load the resource on the next call if the old call has already completed? If so, then the cached Task<T>/AsyncLazy<T> needs to be replaced when the call completes.
Is caching errors OK, or should the next call always retry any previous errors?
Related
I have an async method Save which internally calls CompleteTaskAsync method as below:
public async void Save()
{
await CompleteTaskAsync();
MessageBox.Show("TaskCompleted");
}
private async Task CompleteTaskAsync()
{
int someResult = await GetResultAsync();//Does some calculation which take few seconds.
await FinalSave(someResult);//Note: This method also interact UI internally
}
CompleteTaskAsync calls two methods in which second method is using output of the first.
In current case MessageBox is coming just after calling first method(GetResultAsync), without calling second method(FinalSave).
I want both await method to be executed before showing the message. Is there any way to execute both await methods before returning to its calling method.
MessageBox.Show("TaskCompleted"); will not be called until the Task instance returned by CompleteTaskAsync is completed, which will in turn not be completed until both of the Task instances returned by GetResultAsync and FinalSave are completed.
Your use of async/await and the behavior you are requesting are consistent. Can you give any more information? I believe your problem does not lie in the code shown.
I have the following async long running method inside my asp.net mvc-5 web application :-
public async Task<ScanResult> ScanAsync(string FQDN)
{
// sample of the operation i am doing
var c = await context.SingleOrDefaultAsync(a=>a.id == 1);
var list = await context.Employees.ToListAsync();
await context.SaveChangesAsync();
//etc..
}
and i am using Hangfire tool which support running background jobs to call this async method on timely basis, but un-fortuntly the hangefire tool does not support calling async methods directly . so to overcome this problem i created a sync version of the above method , as follow:-
public void Scan()
{
ScanAsync("test").Wait();
}
then from the HangFire scheduler i am calling the sync method as follow:-
RecurringJob.AddOrUpdate(() => ss.Scan(), Cron.Minutely);
so i know that using .Wait() will mainly occupy the iis thread during the method execution ,, but as i mentioned i need to do it in this way as i can not directly call an async TASK inside the hangefire scheduler .
so what will happen when i use .Wait() to call the async method ?, will the whole method's operations be done in a sync way ? for example as shown above i have three async operations inside the ScanAsync() ;SingleOrDefualtAsync,ToListAsync & SaveChangesAsync, so will they be executed in sync way because i am calling the ScanAsync method using .wait() ?
so what will happen when i use .Wait() to call the async method ?,
will the whole method's operations be done in a sync way ? for example
as shown above i have three async operations inside the ScanAsync()
;SingleOrDefualtAsync,ToListAsync & SaveChangesAsync, so will they be
executed in sync way because i am calling the ScanAsync method using
.wait() ?
The methods querying the database will still be executed asynchronously, but the fact that you're calling Wait means that even though you're releasing the thread, it wont return to the ASP.NET ThreadPool as you're halting it.
This is also a potential for deadlocks, as ASP.NET has a custom synchronization context which makes sure the context of the request is availiable when in a continuation of an async call.
I would recommend that instead, you'd use the synchronous API provided by entity-framework, as you won't actually be enjoying the scalability one can get from asynchronous calls.
Edit:
In the comments, you asked:
As i am currently doing with hangefire eliminate the async effect ? if yes then will it be better to use sync methods instead ? or using sync or async with hangeffire will be exactly the same
First, you have to understand what the benefits of async are. You don't do it because it's cool, you do it because it serves a purpose. What is that purpose? Being able to scale under load. How does it do that? When you await an async method, control is yielded back to the caller. For example, you have an incoming request, you query you database. You can either sit there and wait for the query to finish, or you can re-use that thread to serve more incomong requests. That's the true power.
If you don't actually plan on receiving a decent amount of requests (such that you'll starve the thread-pool), you won't actually see any benefit from async. Currently, the way you've implemented it, you won't see any of those benefits because you're blocking the async calls. All you'll see, possibly, are deadlocks.
This very much depends on the way HangFire is implemented. If it just queuing tasks to be invoked in ThreadPool the only effect will be, that one of your threads will be blocked until the request is ended. However if there is a custom SynchronizationContext this can lead to a serious deadlock.
Consider, if you really want to wait for your scheduled job to be done. Maybe all you want is just a fire and forget pattern. This way your method will be like:
public void Scan()
{
ScanAsync("test"); // smoothly ignore the task
}
If you do need to wait, you can instead try using async void method:
public async void Scan()
{
await ScanAsync("test");
DoSomeOtherJob();
}
There are many controversies about using async void as you cannot wait for this method to end, nor you can handle possible errors.
However, in event driven application this can be the only way. For more informations you can refer to: Async Void, ASP.Net, and Count of Outstanding Operations
this is a follow on from a previous question I posted Calling an async method using a Task.Run seems wrong?
I thought the code written by the contractor was wrong but following on from the answers provided I'm now wondering if it's the libraries fault. This library exposes two methods that I need to use. One returns a "template" and one consumes part of this template (it does in my implementation anyway). But both are async methods returning Tasks.
To explain my library has methods:
public Task<TemplateInfo> TemplateInfo(TemplateInfoRequest request);
public Task<List<EmailResult>> SendMessageTemplate(SendMessageTemplateRequest request);
I need to call these thus:
public bool SendMessage()
{
var template = TemplateInfo(...);
var message = //use template to create message
var sendResponse = SendMessageTemplate(message);
return sendResponse.Count > 0;
}
So the second call relies on the first. This is where the async doesn't make sense to me. I can't and don't want to run these in parallel. I want to run them in sequence. I want my method to by synchonous.
An answer in my previous question also states:
Since you're blocking on an async method (which you shouldn't do)
there is a chance you'll deadlock.
So how do I access these async methods in such a way that they are processed in turn and return a synconhonous result but do not cause deadlocks?
Async doesn't (necessarily) means parallel.
You can call both async method sequentially without them running in parallel. Simply call the first and await the returned task and then do the same with the second.
var template = await TemplateInfo(...);
var message = //use template to create message
var sendResponse = await SendMessageTemplate(message);
This is still useful compared to synchronous code because while the asynchronous operation is "running" there's no thread needed and so your threads can go work on other parts of your application.
If you would call both and only then await the returned tasks you will (maybe) run in parallel:
var templateTask = TemplateInfo(...);
var sendResponseTask = SendMessageTemplate(message);
await templateTask;
await sendResponseTask;
I'm not sure if this is a SignalR issue or an async/await issue. When my client app (WPF) starts up, it does some initialisation:-
public async void Initialise()
{
// Get data from the server - async, as it may be long-running.
var data = await _hubProxy.Invoke<FooData>("Method1");
_dataProcessor.ProcessData(data);
}
The _dataProcessor is a helper class that does some stuff with the data passed to it, then at some point calls a different server method using a line similar to:-
var moreData = _hubProxy.Invoke<BarData>("Method2").Result;
None of the code in the helper class is async.
The first server invoke (in Initialise()) works fine - it gets back the data and passes it to the helper class. This proceeds without issue until its invoke - it gets called but never returns, and the thread never proceeds past this line. I've put a breakpoint in the server method and can confirm that it is being called and returning a value, but for some reason this is not getting back to the client.
The strange thing is, if I take out the async/await keywords in the Initialise() method, everything works fine. What am I doing wrong? Why would these keywords affect the synchronous code in the helper class?
(I realise you shouldn't normally use async void, but as the Initialise() method is "fire and forget", I thought it was okay in this scenario).
This line causes a deadlock on the UI thread:
var moreData = _hubProxy.Invoke<BarData>("Method2").Result;
Make ProcessData an async method and await _hubProxy.Invoke inside it:
var moreData = await _hubProxy.Invoke<BarData>("Method2");
Then, await _dataProcessor.ProcessData in your Initialise:
await _dataProcessor.ProcessData(data);
Make sure you don't use .Result or .Wait anywhere else.
Another way of solving it is just this:
public async void Initialise()
{
// Get data from the server - async, as it may be long-running.
var data = await _hubProxy.Invoke<FooData>("Method1").ConfigureAwait(false);
_dataProcessor.ProcessData(data);
}
Note ConfigureAwait(false). In this case the continuation after await will happen on a non-UI thread. This will eliminate the deadlock, but this is not an ideal solution, rather a workaround. Moreover, your logic may require the continuation on the UI thread, for UI access or some thread-safety concerns.
The best solution would be to use both ConfigureAwait(false) (if possible) and avoid blocking with .Result or .Wait, at the same time.
I want to use recent C# 5.0 async methods, however some specific way.
Consider following example code:
public abstract class SomeBaseProvider : ISomeProvider
{
public abstract Task<string> Process(SomeParameters parameters);
}
public class SomeConcreteProvider1 : SomeBaseProvider
{
// in this method I want to minimize any overhead to create / run Task
// NOTE: I remove here async from method signature, because basically I want to run
// method to run in sync!
public override Task<string> Process(SomeParameters parameters) {
string result = "string which I don't need any async code to get";
return Task.Run(() => result);
}
}
public class SomeConcreteProvider2 : SomeBaseProvider
{
// in this method, it's OK for me to use async / await
public async override Task<string> Process(SomeParameters parameters) {
var data = await new WebClient().DownloadDataTaskAsync(urlToRequest);
string result = // ... here we convert data byte[] to string some way
return result;
}
}
Now how I am going to use async methods (you can ignore fact that consumer actually ASP.NET MVC4 app in my case... it can be anything):
public class SomeAsyncController : AsyncController
{
public async Task<ActionResult> SomethingAsync(string providerId)
{
// we just get here one of providers I define above
var provider = SomeService.GetProvider(providerId);
// we try to execute here Process method in async.
// However we might want to actually do it in sync instead, if
// provider is actually SomeConcreteProvider1 object.
string result = await provider.Process(new SomeParameters(...));
return Content(result);
}
}
As you can see I have 2 implementations, each one will perform differently: one I want to run in async and do not block thread (SomeConcreteProvider2), while another one I want to be able to run in sync and do not create any Task object etc (which I fail to code in code above, i.e. I do create new Task here!).
There are questions already like How would I run an async Task<T> method synchronously?. However I don't want to run something in sync... I want to avoid any overhead if I know at code time (i.e. before runtime) that some methods implementations will NOT actually be async and will not need to use any threads / I/O completion ports etc. If you check code above, its easy to see that method in SomeConcreteProvider1 basically will construct some string (html), can do it very quickly at the same execution thread. However same method in SomeConcreteProvider2 will need to create Web Request, get Web Response and process it someway and I do want to make at least Web Request in Async to avoid blocking of whole thread during request time (may be quit long time actually).
So the question is: how to organize my code (different method signatures or different implementations, or?) to be able to decide how to execute method and avoid ANY possible overhead which caused for example by Task.Run(...) in SomeConcreteProvider1.Process method?
Update 1: obvious solutions (I think up some of them during question process), such as for example to add some static property to each of providers (say 'isAsyncImplementation') and then check that property to decide how to run method (with await or without await in controller action) have some overhead too :D I want something better if possible :D
In your first case, I would recommend returning:
Task.FromResult(result)
which returns a ready-completed task.
http://msdn.microsoft.com/en-us/library/hh194922%28v=vs.110%29.aspx
Your design looks fine.
For the SomeConcreteProvider1 case, you can use a TaskCompletionSource
This returns a Task without requiring concurrency.
Also, in the consumer code, await will not yield if the Task has already completed. This is called the "fast path" and effectively makes the method synchronous.