I'm trying to prevent freezing application interface at waiting moment, so I code this function, but it doesn't work.
Where is the mistake, and how can I solve this?
async void buttonBlocking()
{
await Task.Run(() =>
{
if (irTryCounter % 3 == 0)
{
this.Dispatcher.Invoke(() =>
{
grdLogin.IsEnabled = false;
Thread.Sleep(10000);
grdLogin.IsEnabled = true;
});
}
});
}
If your buttonBlocking is invoked from UI thread, then you can simplify your code:
async void buttonBlocking()
{
if (irTryCounter % 3 == 0)
{
grdLogin.IsEnabled = false;
await Task.Delay(10000);
grdLogin.IsEnabled = true;
}
}
This way it won't block your UI
The mistake, as pointed by Matthew Watson in a comment, is that the Dispatcher.Invoke() will run the code on the UI thread, so the Thread.Sleep will be blocking the UI thread.
Now let's see how this problem can be fixed. I am assuming that your code is an event handler, and you want this handler to run asynchronously. This is the only valid scenario for using an async void method. In any other case you should use async Task.
private async void Button1_Click(object sender, RoutedEventArgs e)
{
if (irTryCounter % 3 == 0)
{
grdLogin.IsEnabled = false;
await Task.Run(() =>
{
// Here you can run any code that takes a long time to complete
// Any interaction with UI controls is forbidden here
// This code will run on the thread-pool, not on the UI thread
Thread.Sleep(10000);
});
grdLogin.IsEnabled = true;
}
}
In case the long-running operation returns a result that needs to be passed to the UI thread, use the Task.Run overload that returns a Task<TResult>:
int result = await Task.Run(() =>
{
Thread.Sleep(10000);
return 13;
});
// We are back on the UI thread, and the result is available for presentation
I am assuming that the Thread.Sleep(10000) is a placeholder for an actual synchronous operation that takes a long time to complete. It would be even better if this operation can be performed asynchronously, because it would not require consuming a ThreadPool thread for the whole duration of the operation. As an example, a delay can be performed asynchronously by using the Task.Delay method:
await Task.Run(async () =>
{
await Task.Delay(10000);
});
In this case the Task.Run wrapper may seem redundant, but actually it's not. Wrapping your asynchronous code in a Task.Run protects your application from badly behaving asynchronous APIs that block the current thread. The overhead of including the wrapper is minuscule, and should have no noticeable effect in a WinForms/WPF application. The exception is ASP.NET applications, where Task.Runing is inadvisable.
Related
I read this article with this example:
class MyService
{
/// <summary>
/// This method is CPU-bound!
/// </summary>
public async Task<int> PredictStockMarketAsync()
{
// Do some I/O first.
await Task.Delay(1000);
// Tons of work to do in here!
for (int i = 0; i != 10000000; ++i)
;
// Possibly some more I/O here.
await Task.Delay(1000);
// More work.
for (int i = 0; i != 10000000; ++i)
;
return 42;
}
}
It then describes how to call it depending on if you're using a UI based app or an ASP.NET app:
//UI based app:
private async void MyButton_Click(object sender, EventArgs e)
{
await Task.Run(() => myService.PredictStockMarketAsync());
}
//ASP.NET:
public class StockMarketController: Controller
{
public async Task<ActionResult> IndexAsync()
{
var result = await myService.PredictStockMarketAsync();
return View(result);
}
}
Why do you need to use Task.Run() to execute PredictStockMarketAsync() in the UI based app?
Wouldn't using await myService.PredictStockMarketAsync(); in a UI based app also not block the UI thread?
By default, when you await an incomplete operation, the sync-context is captured (if present). Then, when reactivated by the completion of the async work, that captured sync-context is used to marshal the work. Many scenarios don't have a sync-context, but UI applications such as winforms and WPF do, and the sync-context represents the UI thread (basically: this is so that the default behaviour becomes "my code works" rather than "I get cross-thread exceptions when talking to the UI in my async method"). Essentially, this means that when you await Task.Delay(1000) from a UI thread, it pauses for 1000ms (releasing the UI thread) but then resumes on the UI thread. This means that you "Tons of work to do in here" happens on the UI thread, blocking it.
Usually, the fix for this is simple: add .ConfigureAwait(false), which disables sync-context capture:
await Task.Delay(1000).ConfigureAwait(false);
(usually: add this after all await in that method)
Note that you should only do this when you know that you don't need what the sync-context offers. In particular: that you aren't going to try to touch the UI afterwards. If you do need to talk to the UI, you'll have to use the UI dispatcher explicitly.
When you used Task.Run(...), you escaped the sync-context via a different route - i.e. by not starting on the UI thread (the sync-context is specified via the active thread).
Factory.StartNew leads to code execution blockage when I don't used Thread.Sleep(20);
I tried the following:
Thread.Sleep() - This works with Factory.StartNew & produces desirable result
Task.Delay(20) - This doesn't work with Factory.StartNew
Task<bool>.Run - Using this instead of Factory.StartNew doesn't make any difference
The code:
private async Task<bool> GetStatus()
{
var MyTask = Task<bool>.Factory.StartNew( () =>
//var MyTask = Task<bool>.Run( () => // Using Task.Run doesn't make any
//difference
{
while (true)
{
if (EventStatus.ToString() == "Rejected")
break;
if (EventStatus.ToString() == "Error")
break;
Thread.Sleep(20);// This gives the desirable result.Removing it
//causes application to hang
//Task.Delay(20);// This line doesn't make any difference
}
return true;
});
MyTask.Wait();
return await MyTask;
}
If I use Task.Factory.StartNew without using Thread.Sleep(20) code gets stuck in endless loop.
How can I improve code and get it to work without using Thread.Sleep(20) ?
I tried Task.Factory.StartNew specifying TaskScheduler but that caused code to hang too.
First, don't use StartNew. It's dangerous. Use Task.Run instead.
Second, the reason you're seeing and endless loop is that Task.Delay just starts a timer and returns a task that completes when that timer fires. If you want the code to actually wait for the timer, then you need to await that task. Also, EventStatus is being accessed from multiple threads without protection, which is not good. You'll need to add a lock to fix this permanently:
private async Task<bool> GetStatus()
{
var task = Task.Run(async () =>
{
while (true)
{
// TODO: add lock for EventStatus
if (EventStatus.ToString() == "Rejected")
break;
if (EventStatus.ToString() == "Error")
break;
await Task.Delay(20);
}
return true;
});
return await task;
}
As a final note, I would get rid of this entirely. Instead of polling for EventStatus to change, make it an actual "signal". E.g., assuming EventStatus is set once, then a TaskCompletionSource<bool> would work fine.
This question is for learning purposes. I am not in developing anything for sure.
I have two long running CPU-bound operations (JobA and JobB). Both do not interact with the GUI. Unlike Task.FromResult that completes immediately at the await expression, my Task.Run(()=>JobA()).ConfigureAwait(false) will return control to the caller and causes the continuation to be executed in non-GUI thread (because of ConfigureAwait(false)).
static void JobA()
{
for (int i = 0; i < int.MaxValue; i++) ;
}
static void JobB()
{
for (int i = 0; i < int.MaxValue; i++) ;
}
private static async Task Async()
{
await Task.Run(()=>JobA()).ConfigureAwait(false);
JobB();
//await Task.Run(() => JobB());
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
await Async();
}
Question
In my understanding, wrapping JobB with Task.Run as in the second case below is unnecessary because the continuation is already guaranteed to run in non-GUI thread.
private static async Task Async()
{
await Task.Run(()=>JobA()).ConfigureAwait(false);
JobB();
}
private static async Task Async()
{
await Task.Run(()=>JobA()).ConfigureAwait(false);
await Task.Run(() => JobB());
}
Exception behavior in asynchronous is a bit tricky so I am asking this question because I want to know whether eliding is risky when exception occurs. If there is no such risk, I will delete this question.
my Task.Run(()=>JobA()).ConfigureAwait(false) will return control to the caller and causes the continuation to be executed in non-GUI thread (because of ConfigureAwait(false))
Really? Are you sure?
One interesting aspect of await is that it behaves synchronously if possible. So if the task has already completed by the time await checks it, then await will continue running synchronously. In this scenario, ConfigureAwait has no effect.
Notably, this can happen when you have different computers with different CPU speeds, or memory available, or cache behavior. With a dose of Murphy's Law, you end up with a production issue that you can't reproduce, which is always fun.
So, I never rely on ConfigureAwait(false) to guarantee that any code is running on a thread pool thread. That's what Task.Run is for. For the simple case you posted, you can do one job after another within the Task.Run: await Task.Run(() => { JobA(); JobB(); });
This is for an iOS app written in Xamarin. All my application code runs in the main thread (i.e. the UI thread).
The UI code does something as follows:
public async void ButtonClicked()
{
StartSpinner();
var data = await UpdateData();
StopSpinner();
UpdateScreen(data);
}
The UpdateData function does something as follows:
public Task<Data> UpdateData()
{
var data = await FetchFromServer();
TriggerCacheUpdate();
return data;
}
TriggerCacheUpdate ends up calling the following function defined below
public Task RefreshCache()
{
var data = await FetchMoreDataFromServer();
UpdateInternalDataStructures();
}
My question is how should TriggerCacheUpdate be written? The requirements are:
Can't be async, I don't want UpdateData and consequently
ButtonClicked to wait for RefreshCache to complete before
continuing.
UpdateInternalDataStructures needs to execute on the main (UI) thread, i.e. the thread that all the other code shown above executes on.
Here are a few alternatives I came up with:
public void TriggerCacheUpdate()
{
RefreshCache();
}
The above works but generates a compiler warning. Moreover exception handling from RefreshCache doesn't work.
public void TriggerCacheUpdate()
{
Task.Run(async() =>
{
await RefreshCache();
});
}
The above violates requirement 2 as UpdateInternalDataStructures is not executed on the same thread as everything else.
A possible alternative that I believe works is:
private event EventHandler Done;
public void TriggerCacheUpdate()
{
this.task = RefreshCache();
Done += async(sender, e) => await this.task;
}
Task RefreshCache() {
var data = await FetchMoreDataFromServer();
UpdateInternalDataStructures();
if (Done != null) {
Done(this, EventArgs.Empty);
}
}
Does the above work? I haven't ran into any problems thus far with my limited testing. Is there a better way to write TriggerCacheUpdate?
It's hard to say without being able to test it but it looks like your trigger cache update method is fine, it's your RefreshCache that needs to change. Inside of RefreshCache you are not waiting in the UI thread for the result of "data" to return so set the ConfigureAwait to false.
public async Task RefreshCache()
{
var data = await FetchMoreDataFromServer().ConfigureAwait(false);
UpdateInternalDataStructures();
}
Your event handler is async. That means, that even if you await for a Task to complete, that your UI remains responsive. So even if you would await for the TriggerCacheUpdate to return, your UI would remain responsive.
However, if you are really certain that you are not interested in the result of TriggerCachUpdate, then you could start a Task without waiting for it:
public Task<Data> UpdateData()
{
var data = await FetchFromServer();
Task.Run( () => TriggerCacheUpdate());
return data;
}
Note: careful: you don't know when TriggerCachUpdate is finished, not even if it ended successfully or threw an exception. Also: check what happens if you start a new TriggerCacheUpdate task while the previous one is not finished yet.
For those who want to use Task.Factory.StartNew, see the discussion about it in MSDN:
Task.Run vs Task.Factory.StartNew
When awaiting Dispatcher.RunAsync the continuation occurs when the work is scheduled, not when the work has completed. How can I await the work completing?
Edit
My original question assumed the premature continuation was caused by the design of the API, so here's the real question.
When awaiting Dispatcher.RunAsync using an asynchronous delegate, using await within the delegate's code, the continuation occurs when the await is encountered, not when the work has completed. How can I await the work completing?
Edit 2
One reason you may need to dispatch work that's already on the UI thread is to workaround subtle timing and layout issues. It's quite common for values of sizes and positions of elements in the visual tree to be in flux and scheduling work for a later iteration of the UI can help.
I found the following suggestion on a Microsoft github repository: How to await a UI task sent from a background thread.
Setup
Define this extension method for the CoreDispatcher:
using System;
using System.Threading.Tasks;
using Windows.UI.Core;
public static class DispatcherTaskExtensions
{
public static async Task<T> RunTaskAsync<T>(this CoreDispatcher dispatcher,
Func<Task<T>> func, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal)
{
var taskCompletionSource = new TaskCompletionSource<T>();
await dispatcher.RunAsync(priority, async () =>
{
try
{
taskCompletionSource.SetResult(await func());
}
catch (Exception ex)
{
taskCompletionSource.SetException(ex);
}
});
return await taskCompletionSource.Task;
}
// There is no TaskCompletionSource<void> so we use a bool that we throw away.
public static async Task RunTaskAsync(this CoreDispatcher dispatcher,
Func<Task> func, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) =>
await RunTaskAsync(dispatcher, async () => { await func(); return false; }, priority);
}
Once you do that, all you need to do is use the new RunTaskAsync method to have your background task await on the UI work.
Usage example
Let's pretend that this is the method that needs to run in the UI thread. Pay attention to the debug statements, which will help follow the flow:
public static async Task<string> ShowMessageAsync()
{
// Set up a MessageDialog
var popup = new Windows.UI.Popups.MessageDialog("Question", "Please pick a button to continue");
popup.Commands.Add(new Windows.UI.Popups.UICommand("Button 1"));
popup.Commands.Add(new Windows.UI.Popups.UICommand("Button 2"));
popup.CancelCommandIndex = 0;
// About to show the dialog
Debug.WriteLine("Waiting for user choice...");
var command = await popup.ShowAsync();
// Dialog has been dismissed by the user
Debug.WriteLine("User has made a choice. Returning result.");
return command.Label;
}
To await that from your background thread, this is how you would use RunTaskAsync:
// Background thread calls this method
public async void Object_Callback()
{
Debug.WriteLine("Object_Callback() has been called.");
// Do the UI work, and await for it to complete before continuing execution
var buttonLabel = await Dispatcher.RunTaskAsync(ShowMessageAsync);
Debug.WriteLine($"Object_Callback() is running again. User clicked {buttonLabel}.");
}
The output then looks like this:
Object_Callback() has been called.
Waiting for user choice...
User has made a choice. Returning result.
Object_Callback() is running again. User clicked Button 1.
Your question is assuming that you want to schedule (and wait for) work on a UI thread from a background thread.
You'll usually find your code is much cleaner and easier to understand (and it will definitely be more portable) if you have the UI be the "master" and the background threads be the "slaves".
So, instead of having a background thread await some operation for the UI thread to do (using the awkward and unportable Dispatcher.RunAsync), you'll have the UI thread await some operation for the background thread to do (using the portable, made-for-async Task.Run).
You can wrap the call to RunAsync in your own asynchronous method that can be awaited and control the completion of the task and thus the continuation of awaiting callers yourself.
Since async-await is centred on the Task type, you must orchestrate the work using this type. However, usually a Task schedules itself to run on a threadpool thread and so it cannot be used to schedule UI work.
However, the TaskCompletionSource type was invented to act as a kind of puppeteer to an unscheduled Task. In other words, a TaskCompletionSource can create a dummy Task that is not scheduled to do anything, but via methods on the TaskCompletionSource can appear to be running and completing like a normal job.
See this example.
public Task PlayDemoAsync()
{
var completionSource = new TaskCompletionSource<bool>();
this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
{
try
{
foreach (var ppc in this.Plots.Select(p => this.TransformPlot(p, this.RenderSize)))
{
// For each subsequent stroke plot, we need to start a new figure.
//
if (this.Sketch.DrawingPoints.Any())
this.Sketch.StartNewFigure(ppc.First().Position);
foreach (var point in ppc)
{
await Task.Delay(100);
this.Sketch.DrawingPoints.Add(point.Position);
}
}
completionSource.SetResult(true);
}
catch (Exception e)
{
completionSource.SetException(e);
}
});
return (Task)completionSource.Task;
}
Note: the main work being done on the UI thread is just some lines being drawn on screen every 100ms.
A TaskCompletionSource is created as the puppet master. Look near the end and you'll see that it has a Task property that is returned to the caller. Returning Task satisfies the compilers needs and makes the method awaitable and asynchronous.
However, the Task is just a puppet, a proxy for the actual work going on in the UI thread.
See how in that main UI delegate I use the TaskCompletionSource.SetResult method to force a result into the Task (since returned to the caller) and communicate that work has finished.
If there's an error, I use SetException to 'pull another string' and make it appear that an exception has bubbled-up in the puppet Task.
The async-await subsystem knows no different and so it works as you'd expect.
Edit
As prompted by svick, if the method was designed to be callable only from the UI thread, then this would suffice:
/// <summary>
/// Begins a demonstration drawing of the asterism.
/// </summary>
public async Task PlayDemoAsync()
{
if (this.Sketch != null)
{
foreach (var ppc in this.Plots.Select(p => this.TransformPlot(p, this.RenderSize)))
{
// For each subsequent stroke plot, we need to start a new figure.
//
if (this.Sketch.DrawingPoints.Any())
this.Sketch.StartNewFigure(ppc.First().Position);
foreach (var point in ppc)
{
await Task.Delay(100);
this.Sketch.DrawingPoints.Add(point.Position);
}
}
}
}
A nice way to work the clean way #StephenCleary suggests even if you have to start from a worker thread for some reason, is to use a simple helper object. With the object below you can write code like this:
await DispatchToUIThread.Awaiter;
// Now you're running on the UI thread, so this code is safe:
this.textBox.Text = text;
In your App.OnLaunched you have to initialize the object:
DispatchToUIThread.Initialize(rootFrame.Dispatcher);
The theory behind the code below you can find at await anything;
public class DispatchToUIThread : INotifyCompletion
{
private readonly CoreDispatcher dispatcher;
public static DispatchToUIThread Awaiter { get; private set; }
private DispatchToUIThread(CoreDispatcher dispatcher)
{
this.dispatcher = dispatcher;
}
[CLSCompliant(false)]
public static void Initialize(CoreDispatcher dispatcher)
{
if (dispatcher == null) throw new ArgumentNullException("dispatcher");
Awaiter = new DispatchToUIThread(dispatcher);
}
public DispatchToUIThread GetAwaiter()
{
return this;
}
public bool IsCompleted
{
get { return this.dispatcher.HasThreadAccess; }
}
public async void OnCompleted(Action continuation)
{
if (continuation == null) throw new ArgumentNullException("continuation");
await this.dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => continuation());
}
public void GetResult() { }
}