I have a small project - WinForms
On .net frameWork - just a small test :
private void button9_Click(object sender, EventArgs e)
{
string text = GetTitleAsync().Result;
button9.Text = text;
}
private async Task<string> GetTitleAsync()
{
await Task.Delay(3000);
return "Hello!";
}
As I ran the application ,
Clicking the button: "button9" - caused a dead lock,
(since the thread was hung on the ".result" )
Writing GetTitleAsync() this way:
private async Task<string> GetTitleAsync()
{
await Task.Delay(3000).ConfigureAwait(false);
return "Hello!";
}
solved the deadlock - and the application ran ok.
But I don't understand how ?
I would have expected, that using ".ConfigureAwait(false)" would cause a
situation in which :
"button9.Text = text;" is executed on a different thread than
the one, on which the UI was created,
and an excpetion would be throwed !
but it works excellent !
how??
I would have expected, that using ".ConfigureAwait(false)" would cause a situation in which "button9.Text = text;" is executed on a different thread than the one, on which the UI was created, and an excpetion would be throwed ! but it works excellent ! how??
I recommend reading my async/await intro; I try to include everything you need to know about async/await and their contexts, without getting into too much detail for an intro.
Specifically, there are two points from that post that are worth noting:
Every async method begins executing synchronously, on the calling thread.
await captures a context unless you use ConfigureAwait(false).
So, walking through this code:
private void button9_Click(object sender, EventArgs e)
{
string text = GetTitleAsync().Result;
button9.Text = text;
}
private async Task<string> GetTitleAsync()
{
await Task.Delay(3000).ConfigureAwait(false);
return "Hello!";
}
This is what happens, in order, with special attention paid to which thread runs which code:
button9_Click calls GetTitleAsync() on the UI thread.
GetTitleAsync() calls Task.Delay(3000) and gets back a task that will complete in 3 seconds.
GetTitleAsync() calls ConfigureAwait(false) and gets back a configured awaiter that will not resume on the current (UI) context.
GetTitleAsync() uses await to asynchronously wait for the task to complete. This await will not resume on the current (UI) context because the await has been configured not to.
The await examines the task and sees it is not complete, so it returns an incomplete Task<string> to its caller.
button9_Click calls .Result on that task. This blocks the UI thread until that task completes (i.e., GetTitleAsync() is finished executing).
Three seconds later, the task returned from Task.Delay(3000) completes.
GetTitleAsync() resumes executing after its await. Since this was a configured await, it continues executing on a thread pool thread.
GetTitleAsync() returns "Hello!". This is done on a thread pool thread.
By returning a value, GetTitleAsync() is now complete, and the Task<string> that it returned earlier is now completed with a result value. This completion also happens on a thread pool thread.
Since the task is now complete, the UI thread is no longer blocked, and it continues executing button9_Click.
button9_Click executes button9.Text = text; on the UI thread.
Related
I am quite a beginner with ReactiveUI and have a strange behavior with a ReactiveCommand.
I want to query data from a database that currently does not support
asynchronous operations. Since we want to exchange the database in the
future with an asynchronous interface I want to write everything as
if the database already would allow async operations. As far as I understand
that would mean that I wrap my database calls at the lowest level in
a Task.
I have a button which is bound to a ReactiveCommand and the command
starts the database query. While the query lasts I want to show some
sort of animation.
The problem is that whatever I tried, the query blocks my UI thread.
Here is part of my code:
public ReactiveCommand<Unit, Unit> StartExportCommand { get; }
//The constructor of my view model
public ExportDataViewModel(IDataRepository dr)
{
this.dr = dr;
//...
StartExportCommand = ReactiveCommand.CreateFromTask(() => StartExport());
//...
}
private async Task StartExport()
{
try
{
Status = "Querying data from database...";
//Interestingly without this call the Status message would not even be shown!
//The delay seems to give the system the opportunity to at least update the
//label in the UI that is bound to "Status".
await Task.Delay(100);
//### This is the call that blocks the UI thread for several seconds ###
var result = await dr.GetValues();
//do something with result...
Status = "Successfully completed";
}
catch(Exception ex)
{
Status = "Failed!";
//do whatever else is necessary
}
}
//This is the GetValues method of the implementation of the IDataRepository.
//The dictionary maps measured values to measuring points but that should not matter here.
//ValuesDto is just some container for the values.
public Task<IDictionary<int, ValuesDto>> GetValues()
{
//...
return Task<IDictionary<int, ValuesDto>>.Factory.StartNew(() =>
{
//### here is where the blocking calls to the database
//### specific APIs take place
return result;
}, TaskCreationOptions.LongRunning);
}
I don't understand why this code is blocking the UI thread although I am wrapping
the long running query in a Task.
Is there something wrong with this pattern or should I go another way with Observables?
Edit 1
I am aware of the fact that async != threads. I thought, however, that Task with the TaskCreationOptions.LongRunning would make the blocking code run on a thread pool thread.
Edit 2
As recommended by Andy I set a breakpoint inside my task and had a look into the Debug Threads window. It tells me that Task is running on a worker thread. Still my UI is blocking.
my application is WPf and we have data service.
I would like to call async data service task to do some work and return once it done. while async task is doing his job my client can do other work.
but when i would like to call 10 same task by for loop and i want to do each task one after the other task but not parallel. Also my client can continue other work till all 10 task get finished.
if i use task[i].wait() will not allow my client to continue other work. client cannot do anything else till each task get done.
Blocking calls like .Wait() and .Result wont let the UI continue
Use async/await, like for example in a button click event
public async void btn_Clicked(object sender, EventArgs args) {
for (int i = 0; i < someParameter; i++) {
await importExportServiceClient.ClientEntryImportExportAsync(ImpExpobj, start, end, chunk);//for running task to finish
}
}
each task will be awaited in turn without blocking the client. Allowing the client to continue other work till all tasks are completed.
Reference Async/Await - Best Practices in Asynchronous Programming
Could someone shed some light on an issue I'm having?
I'm working on a wpf project. The scenario is as below:
I need to pop up a window(model window) on main UI thread and then close it. These works are started from another UI thread (to deter user from clicking on the main UI window.) then I close this window. The main code are displayed below. And it works.
As far as I know the close method would not get excuted before ShowDialog() returns (at least this is the case on UI thread, I mean code without dispatcher), does anyone have experience with multithread?
Window window;
private void Button_Click(object sender, RoutedEventArgs e)
{
Thread thread = new Thread(() =>
{
//create a window and let user work from this thread
//code is omitted.
//create another window on main UI thread
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
window = new Window();
window.ShowDialog();
}));
//do some work here
Thread.Sleep(1000);
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
//Thread.Sleep(1000);
window.Close();
}));
});
thread.Start();
}
Thank you for your time!
So if I understand your question correctly, you're saying that this code works exactly the way you want, but you're just trying to understand how (and why) it works?
Here's how it works. First, your thread runs this code:
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
window = new Window();
window.ShowDialog();
}));
That queues your action on the main (UI) thread's dispatcher queue, and then returns immediately: your worker thread continues running.
When the Application first started up (typically via the compiler-generated code that initializes your App.xaml object, though you can also do it explicitly by calling Application.Run), it started its message loop, which goes something like this (pseudocode, very very simplified):
public class Application {
public void Run() {
while (!Exited && action = Dispatcher.DequeueAction())
action();
}
}
So at some point shortly after you queue the action, the UI thread will get around to pulling your action off the queue and running it, at which point your action creates a window and shows it modally.
The modal window now starts its own message loop, which goes something like this (again, very simplified):
public class Window {
public bool? ShowDialog() {
DisableOtherWindowsAndShow();
while (!IsClosed && action = Dispatcher.DequeueAction())
action();
EnableOtherWindowsAndHide();
return DialogResult;
}
}
Later, your worker thread runs this code:
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
window.Close();
}));
Again, your action is queued to the UI thread's dispatcher queue, and then the BeginInvoke call returns immediately and your worker thread continues running.
So sooner or later, the UI thread's message loop will get around to dequeuing and executing your action, which tells the window to close. This has essentially the same effect as the user clicking the title bar's "X" button, which of course is perfectly OK to do even when you're inside a modal dialog. This causes ShowDialog's message loop to terminate (because the window is now closed), at which point the dialog is hidden and the other windows are re-enabled, ShowDialog returns, your original (ShowDialog) action is complete and so returns, and control falls back to the original message loop in Application.Run.
Note that there's one dispatcher queue per thread, not one per message loop. So your "close" action goes into the same queue that your "show dialog" action did. It's a different piece of code doing the message-loop polling now (the one inside ShowDialog instead of the one inside Application.Run), but the basics of the loop are the same.
BeginInvoke is a non-blocking method; it adds the action to the dispatcher queue, and doesn't wait for its completion. You should use Invoke instead, which calls the method synchronously on the dispatcher thread.
I have a silverlight client that communicates with a web service on a server. It has a DoSomething method that does nothing and returns void.
On the client, I call the service and listen to when the response comes back:
proxy.OnDoSomethingCompleted+=OnDoSomethingCompleted;
t0 = Environment.TickCount;
proxy.DoSomethingAsync();
void DoSomething(..)
{
t1 = Environment.TickCount;
}
Network capture indicates the response is sent back within 2ms. However, OnDoSomethingCompleted is not called until 80ms later. Is there a way to change when the callback is executed?
Normally, OnDoSomethingCompleted() would be executed on the UI thread, i.e., behind the scenes, something is calling some code that (conceptually) looks a little like this:
Dispatcher.BeginInvoke(() => OnDoSomethingCompleted());
This means that OnDoSomethingCompleted() won't get executed until the UI thread decides to cooperate and run it. Most of the time that's fine, but there can be times when you want it to run faster. The basic approach is to use a thread pool to make the original call, which means that the response will get handled from the same thread pool (not necessarily ont he same thread). If you can do some real processing in this return method, and don't just automatically marshal it back onto the UI thread, this can speed up your processing somewhat.
Tomek (from the MS WCF team) gives a good example of how do this here:
http://tomasz.janczuk.org/2009/08/improving-performance-of-concurrent-wcf.html
It's also my understanding that the synchronization context for the WCF connection gets set when you first open it. This means that whatever thread the WCF connection is first opened on is the one that will handle all later calls. So in my own code, I do something like this:
// Spin up the connection on a new worker thread.
// According to Tomek, this will cause all WCF calls to be made from this thread.
ManualResetEvent resetEvent = new ManualResetEvent(false);
wcfWorkerThread = new Thread(new ThreadStart(() => InitializeNotificationClient(resetEvent)));
wcfWorkerThread.Name = "WcfWorkerThread";
wcfWorkerThread.Start();
resetEvent.WaitOne();
And then InitializeNotificationClient() looks something like this:
private void InitializeNotificationClient(ManualResetEvent resetEvent = null)
{
try
{
notificationClient = GetRoomServiceClient();
notificationClient.OpenAsync(callback);
notificationClient.InnerChannel.Faulted += new EventHandler(Channel_Faulted);
notificationClient.InnerChannel.Closed += new EventHandler(Channel_Closed);
}
finally
{
// Tell the waiting thread that we're ready.
if (resetEvent != null)
{
resetEvent.Set();
}
}
}
I am trying to reuse some .NET code that performs some calls to a data-access-layer type service. I have managed to package up both the input to the method and the output from the method, but unfortunately the service is called from inside code that I really don't want to rewrite in order to be asynchronous.
Unfortunately, the webservice code generated in Silverlight only produces asynchronous methods, so I was wondering if anyone had working code that managed to work around this?
Note: I don't need to execute the main code path here on the UI thread, but the code in question will expect that calls it makes to the data access layers are synchronous in nature, but the entire job can be mainly executing on a background thread.
I tried the recipe found here: The Easy Way To Synchronously Call WCF Services In Silverlight, but unfortunately it times out and never completes the call.
Or rather, what seems to happen is that the completed event handler is called, but only after the method returns. I am suspecting that the event handler is called from a dispatcher or similar, and since I'm blocking the main thread here, it never completes until the code is actually back into the GUI loop.
Or something like that.
Here's my own version that I wrote before I found the above recipe, but it suffers from the same problem:
public static object ExecuteRequestOnServer(Type dalInterfaceType, string methodName, object[] arguments)
{
string securityToken = "DUMMYTOKEN";
string input = "DUMMYINPUT";
object result = null;
Exception resultException = null;
object evtLock = new object();
var evt = new System.Threading.ManualResetEvent(false);
try
{
var client = new MinGatServices.DataAccessLayerServiceSoapClient();
client.ExecuteRequestCompleted += (s, e) =>
{
resultException = e.Error;
result = e.Result;
lock (evtLock)
{
if (evt != null)
evt.Set();
}
};
client.ExecuteRequestAsync(securityToken, input);
try
{
var didComplete = evt.WaitOne(10000);
if (!didComplete)
throw new TimeoutException("A data access layer web service request timed out (" + dalInterfaceType.Name + "." + methodName + ")");
}
finally
{
client.CloseAsync();
}
}
finally
{
lock (evtLock)
{
evt.Close();
evt = null;
}
}
if (resultException != null)
throw resultException;
else
return result;
}
Basically, both recipes does this:
Set up a ManualResetEvent
Hook into the Completed event
The event handler grabs the result from the service call, and signals the event
The main thread now starts the web service call asynchronously
It then waits for the event to become signalled
However, the event handler is not called until the method above has returned, hence my code that checks for evt != null and such, to avoid TargetInvocationException from killing my program after the method has timed out.
Does anyone know:
... if it is possible at all in Silverlight 3
... what I have done wrong above?
I suspect that the MinGatServices thingy is trying to be helpful by ensuring the ExecuteRequestCompleted is dispatched on the main UI thread.
I also suspect that your code is already executing on the main UI thread which you have blocked. Never block the UI thread in Silverlight, if you need to block the UI use something like the BusyIndicator control.
The knee-jerk answer is "code asynchronously" but that doesn't satisfy your question's requirement.
One possible solution that may be less troublesome is to start the whole chunk of code from whatever user action invokes it on a different thread, using say the BackgroundWorker.
Of course the MinGatServices might be ensuring the callback occurs on the same thread that executed ExecuteRequestAsync in which case you'll need to get that to run on a different thread (jumping back to the UI thread would be acceptable):-
Deployment.Current.Dispatcher.BeginInvoke(() => client.ExecuteRequestAsync(securityToken, input));