Background Workflow:
I have a client (jquery/ajax html page) calling our RESTful WebAPI to get some data (Patient 'encounters' - e.g. admission to a hospital, visit to a clinic, etc.). e.g.
public async Task<string> GetEncounters(string patientId)
{
PatientChart patientChart = await _myService.GetPatientChart(patientId);
string message = string.Empty;
if (patientChart.Encounters.Status == PatientChart.StatusNotApplicable)
{
message = "List of Encounters is not available. A request has been made to retrieve it.";
_myService.GetEncounters(patientId); // async method without call to await
}
return message;
}
Question
What happens the "GetEncounters" call above where the await keyword is not applied?
From my understanding, async methods do NOT generate a new thread
so when the main thread dies, does that mean the call to GetEncounters will abort?
(Behind the scenes, the GetEncounters will fire off a long running process to get data and store it in, e.g. cache, for later retrieval).
If I step through the code, every executes as expected. Likewise, if I add in the await keyword, it also works. (But then I make the caller block)
What's the solution?
i.e. what is the best way to create a background task/thread to execute the code even though the main thread has died?
The solution depends on how reliable you want the work to be. I.e., if you return the "not available" message, how important is it to you that GetEncounters will run?
You should at the very least register the background work with ASP.NET (i.e., HostingEnvironment.QueueBackgroundWorkItem). A more reliable solution would save the background work in storage and have an independent backend for processing. I describe some modern approaches on my blog.
Related
I'm having trouble understanding what runs on the main thread during an async await operation and would be grateful for some answers.
Let's say I have a button that is supposed to log the user in.
it is supposed to block all other user input while the login process transpires, show a progress view and then when the result comes in display it
and here is the method that performs the log in
button_clicked(object sender, EventArgs e) {
do_login(); //I do not await the result
do_some_other_stuff(); //this doesn't actually exist I just put it here to ask my questions
}
async Task do_login() {
string user_name = txtUser.Text;
string password = txtPassword.Text;
show_progress(true); //this is not an async method;
string error = await _login.do_login(user_name, password);//this is an async method that can take up to 20 seconds to complete;
show_progress(false);
if (error != null) {
show_error(error);
} else {
show_next_screen();
}
}
I have two questions on the above example
a) What will be run on the main thread?
If I understand it correctly only _login.do_login will be run on a seperate thread, all others will be on the main thread, is this correct?
b) In what order will the methods be executed?
Again if I understand it correctly, it will be :
do_login()
show_progress(true);
_login.do_login starts;
do_some_other_stuff();
_login.do_login finishes;
show_progress(false);
and it will continue from there
is this correct? if not, how can I achieve such a behaviour?
c) If my code above is correct then why do I keep receiving a warning that do_login() is not awaited? I do not wish to await it I just want it to run what it can and return when it wants, should I ignore that warning?
Technically, depending on the implementation of do_login, everything could run in the main thread. In this case I assume you're contacting a web server, so that part won't, but this is not always true. And asynchronous operation does not necessarily executes in another thread. One operation is asynchronous when:
It doesn't block the calling thread.
Usually, UI threads run an 'event loop'. So an asynchronous task could simply put a new piece of work into the event queue to be executed whenever the scheduler determines, but in the same thread. In this case you don't use two threads, but still, you don't have to wait for the task to complete and you don't know when it'll finish.
To be precise, all the code in your post will run in the main thread. Only the part in do_login that manages the connection with the server, waiting and retrieving data will execute asynchronously.
You're mostly right about the sequence, with a few adjustments:
do_login() (until the await)
login._do_login() starts executing
do_some_other_stuff()
...
login.do_login finishes
show_progress()
The answer to your main question is: it depends. The _login.do_login method will likely be put onto its own thread, but it actually depends on the .NET task scheduler. In WPF and ASP.NET it will be scheduled onto the thread pool if it doesn't immediately return a completed task.
The important part is that you know it will not block execution of the calling (in your case, the main) thread. Your understanding of the method flow is correct since you don't await do_login.
As far as the warning goes; you can mark do_login as async void to avoid it, though generally you only do that for event handlers which can then await a Task returning method. If you do go the async void route; make sure to put a try/catch in as such methods will throw all the way up to the root handler and can cause your app to crash.
So I've achieved localhost WCF Named Pipes communication between client EXE and server EXE. I can call class methods on the server over localhost. So, it's like an IPC/RPC. However, if the server's class method takes a long time to execute, then it's best for me to throw that into a thread so that the server class method finishes and runs this thread in the background. Okay, fine, but then when the thread is finished its long task, I want to alert the client without having to use a timer on the client that would check that class method. A timer hitting a class method is a lot more inefficient than a raised event. It's like I need to raise an event on the client from the server. Is there an easy way to do this or to at least simulate it, without a lot of confusing work?
This is an answer formulated from my comment to the OP's question
You could make your WCF methods asynchonous then it's a simple matter of async/await or do away with WCF completely and use built-in async with NamedPipeClientStream (which is still await compatible). Not to mention a speed boost in the latter when doing away with verbose XML SOAP encoding
OP:
#MickyD You were right on the async/await thing now that I have studied that and implemented a test that works. That allows me to almost simulate a callback on a long running task and with minimal lines of code
e.g. to build upon the OP's answer but to use async/await correctly:
Client code
private async void button1_Click(object sender, EventArgs e) // <-- note async
{
label1.Text = await client.GetDataAsync(textBox1.Text); // <-- note await. New method
}
Now you could be tempted to use Task.Run but doing so is bad because:
Task.Run is best suited for compute-bound operations which we aren't.
Task.Run will at the most use an expensive thread-pool thread
We're performing an I/O operation and as such can benefit from I/O Completion Ports and "there is no thread" philosphy of IOCP present in Task I/O bound operations. As such when we make the server call via GetDataAsync, we don't waste a thread waiting for a result.
WCF Server
Here we simulate a lengthy operation by waiting, but instead of using Sleep which isn't Task-aware, we use Task.Delay which is an awaitable operation.
Task<string> async GetDataAsync (string text)
{
await Task.Delay (Timespan.FromSeconds(5));
return text + " processed";
}
So, let's say you have a button click in your UI that does a WCF synchronous method call on the WCF service, and that synchronous method takes a long time to run. Obviously, you don't want to block the UI from updating while that long running task executes. Naturally, you might be thinking about a callback. As in, you make the call to the server, and the class method on the server spawns a thread and runs that task, and when it's done, it returns back to the client a result via a callback.
To set that all up on WCF involves many complex, confusing, poorly documented steps, actually. But there's a much easier way, and it doesn't involve WCF code at all, and doesn't involve you changing anything on the WCF service, nor editing any WCF configurations. The trick is introduced in .NET 4.5 and greater. It's called async and await. Here is an example of a button click that calls a WCF service method that takes a long time to run and then returns the result when it's finished, and yet the GUI doesn't lock up and can handle other events.
1. First, to simulate a slow task, edit your WCF service project's shared class method and add this line in before the return result so that you can simulate a 5 second pause:
Thread.Sleep(5000); // requires using System.Threading;
In my case, I put that in my GetData() method.
2. Now switch to your WCF client project. You may have a button click handler that looks like this, as an example:
private void button1_Click(object sender, EventArgs e)
{
string returnString = client.GetData(textBox1.Text));
label1.Text = returnString;
}
So, switch that with three minor changes:
a. Add using System.Threading.Tasks;.
b. Change private void... to private async void... on your button click handler.
c. Utilize await Task.Run(...) with your slow method call.
Thus, the code would look like so:
private async void button1_Click(object sender, EventArgs e)
{
// Task.Run() requires "using System.Threading.Tasks;"
string returnString = await Task.Run(() => client.GetData(textBox1.Text));
label1.Text = returnString;
}
The end result is that when you click the button in the WCF client project, the GetData() class method is called on the WCF service project in a background thread, and, when finished, it comes back to that await statement and returns the result to the variable assignment. In my case, I clicked the button and nothing happened for 5 seconds -- the label with the result string didn't change. However, the GUI wasn't locked up -- I could drag the window around, type in other fields, click other form buttons, and so on. So, it's almost like a callback event handler, but not exactly. Still, it serves the same functionality and can be used in place of a callback event handler in most cases. And it involves far less code.
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 have an ASP.NET MVC 3 site that connects to a WCF service. The WCF Service is independent from the site and is hosted in a Windows Service.
Most of the calls are synchronous, so it's not a problem to wait for the WCF to do it's thing.
However, one of those (already implemented) calls takes a bit too long, and, as it essentially does not output anything directly, I wanted to spin it on the service and forget about it.
So I changed my code from:
public ViewResult StartSlowCalculation(CalculationOptions calculationOptions)
{
WcfServiceProxy.DoSlowCalculation(calculationOptions);
ViewBag.Started = true;
return View();
}
to
public ViewResult StartSlowCalculation(CalculationOptions calculationOptions)
{
Task.Run(() =>
{
WcfServiceProxy.DoSlowCalculation(calculationOptions);
});
ViewBag.Started = true;
return View();
}
which, as I understand should start an asynchronous request, and return immediately. Still, the execution is completely synchronous, and the UI is frozen until the operation concludes.
What obvious thing am I missing?
Update:
Also, note that I would prefer not to change the server implementation to an async one, just to de-synchronize the call to the service on the call-site.
Moreover, I've noticed that the StartSlowCalculation method finishes executing, but the server does not return a response until the service method finishes executing.
The WCF Service Proxy just does:
public void DoSlowCalculation(CalculationOptions calculationOptions)
{
//some logging code
Channel.DoSlowCalculation(calculationOptions);
}
so it's completely synchronous, however that shouldn't matter as it should be executed on an independent thread.
A task operation can run in the calling thread, it depends on taskScheduler decision. To help TaskScheduler make a right decision regarding long running call you can specify task creation option TaskCreationOptions.LongRunning.
And you can check whether task operation is running in a separate thread:
int launchedByThreadId = Thread.CurrentThread.ManagedThreadId;
int launchedInThreadId = -1;
Task.Run(() =>
{
launchedInThreadId = Thread.CurrentThread.ManagedThreadId;
WcfServiceProxy.DoSlowCalculation(calculationOptions);
});
// then compare whether thread ids are different
BTW, are you using any kind of Task.Wait() operation? It will block calling thread as well.
EDIT:
You might find following post interesting Is Task.Factory.StartNew() guaranteed to use another thread than the calling thread?
So try out using Task.Factory.StartNew() and specify cancellation token even you do not need it, sounds weird but it seems this guarantees that task will not be run eventually in the calling thread. Correct me If I wrong.
I've done this before.
The most robust way would be to use Asynchronous Controller's, or better yet an independant service such as a WCF service.
But in my experience, i've just needed to do "simple", one-liner task, such as auditing or reporting.
In that example, the easy way - fire off a Task:
public ViewResult StartSlowCalculation(CalculationOptions calculationOptions)
{
//Some Synchronous code.
Task.Factory.StartNew(() =>
{
WcfServiceProxy.DoSlowCalculation(calculationOptions);
});
ViewBag.Started = true;
return View();
}
That's a simple example. You can fire off as many tasks as you want, synchronize them, get notified when they finish, etc.
For more details you can see this links.
https://msdn.microsoft.com/en-us/library/dd321439(v=vs.110).aspx
I have created a Windows 8 Metro App based on the Split Page sample app. However, in the sample app the data is loaded synchronously in the constructor. I'm accessing a text file and therefore need to load the data asynchronously. The constructor looks like this:
public MyDataSource()
{
DataLoaded = false;
LoadData();
}
LoadData() is an asynchronous method that populates the data model. This works fine, and displays the data as is loads it (which is the behavior that I want). The problem occurs when I try testing the suspend and terminate. The problem being that the recovery has the potential to attempt to access the data model before it is populated:
public static MyDataGroup GetGroup(string uniqueId)
{
// If the data hasn't been loaded yet then what?
if (_myDataSource == null)
{
// Where app has been suspended and terminated there is no data available yet
}
// Simple linear search is acceptable for small data sets
var matches = _myDataSource.AllGroups.Where((group) => group.UniqueId.Equals(uniqueId));
if (matches.Count() == 1) return matches.First();
return null;
}
I can fix this by changing the constructor to call LoadData().Wait, but this means that the app locks the UI thread. What I believe I need is a method of getting the recovery code in GetGroup to wait until the data has loaded without locking the UI thread. Is this possible or advisable, and if so, how?
EDIT:
One or two people have suggested caching the task for LoadData(). This is an excellent idea, but the code inside GetGroup is called by the Page State Management section and therefore cannot be async. To get around this, I tried the following:
if (!DataLoaded)
{
//dataLoading = await MyDataSource.LoadData();
dataLoading.RunSynchronously();
}
But this gives me an error:
RunSynchronously may not be called on a task not bound to a delegate, such as the task returned from an asynchronous method.
and
dataLoading.Wait()
just locks the UI.
I think that this sounds like the best option would be if you made the constructor async. But since that's not possible, what you can do instead is to create an async factory method for MyDataSource:
private MyDataSource()
{
DataLoaded = false;
}
public static async Task<MyDataSource> Create()
{
var source = new MyDataSource();
await source.LoadData();
return source;
}
And then initialize _myDataSource using await:
_myDataSource = await MyDataSource.Create();
If, for some reason, you can't do that, you can store the Task returned by the factory method and wait for it in GetGroup():
_myDataSourceTask = MyDataSource.Create();
…
public static async Task<MyDataGroup> GetGroup(string uniqueId)
{
var myDataSource = await _myDataSourceTask;
// Simple linear search is acceptable for small data sets
var matches = myDataSource.AllGroups.Where(group => group.UniqueId == uniqueId);
if (matches.Count() == 1) return matches.First();
return null;
}
If LoadData is async, then store whatever the awaitable is (or make a new one) and expose that (for instance, like a Task) then GetGroup can be marked async and can do var data = await _myDataSource.LoadTask or whatever
I think Svick is the closest to answering the question because of his use of Tasks. Whether you return a Task on the GetGroup method or you return a task on a LoadAsync method probably doesn't matter. What DOES matter is that you capture that task and refer to it later on resume.
The Task class is documented here and you'll notice it has properties like IsCanceled, IsCompleted and IsFaulted. When your constructor kicks off the LoadAsync method you could save the Task it returns as a class-level variable. Later, when your resume code starts, you can check to see whether the Task is still running (i.e. not completed and not faulted). If the Task has completed, you can run your resume code right away. If it hasn't completed yet, you can use Task.ContinueWith to schedule your resume code to be run when the task completes.
I did not check out Windows 8 yet, but I assume it works similar to Windows Phone, assuming you use Silverlight (or WPF) to develop your app, this is not clear to me from your question. In case you use Silverlight:
You need to use the INotifyPropertyChanged interface, and ObservableCollection-s to be able to bind your data to the UI. That way everytime you change your data, the UI will be notified about the changes, and bindings will refresh.
MyDataGroup a pubic property that implements iNotifyPropertyChanged.
UniqueID a public property.
When UniqueID changes set MyDataGroup = null then call a BackGroundWorker to var mathces = but delay that if LoadData(); is working. Since this is in the background the delay will not tie up the UI. In the callback set MyDataGroup and the UI will get notified. Make sure you backgroundworker is cancelable as you will want to cancel it when UniqueID is changed (if it is running).
I do this in WPF so if it does not translate to Metro sorry and I will delete.