I need to process tasks in sequence. So this class subscribed to some events.
When event is handled, asynchronous method must be added to Queue, and it might be executed when all previous tasks completed. At this moment it is realized as here:
But ProccessTasks method stops working when firs event is raised.
public class class view
{
private void ModelUpdatedEventHandler(object sender, EventArgs args)
{
taskQueue.Enqueue(new Task(() => Invalidate()));
}
private void MoveCubesEventHandler(object sender, MoveCheckerEventArgs args)
{
taskQueue.Enqueue(new Task(() => MoveCube(args.Move)));
}
private async Task Invalidate()
{
//code here
}
public async Task MoveChecker(Move move)
{
//code here
}
private async Task ProccessTasks()
{
while (true)
{
while (taskQueue.Count > 0)
{
Task task = taskQueue.Dequeue();
await task;
}
}
}
private async void UserControl_Loaded_1(object sender, RoutedEventArgs e)
{
await Task.Run(() => ProccessTasks());
}
}
The problem is that you're never starting your tasks, ever. You put unstarted tasks into the queue, and then you wait on the unstarted tasks when you pull them out.
Having said that, I would discourage you from just making that one small change. Generally, dealing with unstarted tasks is fairly error prone, as you've seen. I would suggest enqueing Action objects instead of Task objects. When you pull the action out of the queue, you can then either execute it, or if you want to maintain asynchrony, use Task.Run to run it in another thread.
You also don't need to call ProccessTasks using Task.Run. It's already asynchronous, so there's no need to run it in a background thread.
Related
As far as I know async method won't lock user interface. At least it seems to work most of the time. But here it doesn't, and I can't figure out why. It's Avalonia MVVM application. Here is the code:
public class MainWindowViewModel : ReactiveValidationObject
{
public MainWindowViewModel()
{
OnRunClick = ReactiveCommand.CreateFromTask(
() => OnRun(),
this.IsValid());
}
public ReactiveCommand<Unit, Unit> OnRunClick { get; }
private async Task OnRun()
{
await Dispatcher.UIThread.InvokeAsync(() =>
{
DoSomethingForVeryLongTime();
}
}
}
When button is clicked OnRunClick is called, and then user interface stops responding as long as DoSomethingForVeryLongTime runs. Which is not possible to happen, because async ensures interface is still active, yet it happens.
This code runs DoSomethingForVeryLongTime on the UI thread, not a background thread. It issues the call asynchronously but the actual call still runs on the UI thread.
Running something in the background
To actually run in the background, use Task.Run :
private async Task OnRun()
{
await Task.Run(DoSomethingForVeryLongTime);
}
Updating the UI with async/await
Background methods can't modify the UI though, no matter how they're invoked. Execution needs to return to the UI thread somehow. That's what await does in the first place.
If DoSomethingForVeryLongTime can be split into background and UI parts, the background parts can run in the background using Task.Run. Execution will return to the UI thread with await. For example
private async Task OnRun()
{
await DoSomethingForVeryLongTime();
}
async Task DoSomethingForVeryLongTime()
{
for int(i=0;i<1000;i++)
{
//Process in another thread background
await Task.Run(()=>DoSomethingExpensive(i));
//Return to the UI thread and update it
UpdateProgressBar(i);
}
lblStatus.Text="Complete";
}
Updating the UI using IProgress
Another option is to use the IProgress interface and the Progress implementation to report progress from a background thread. Progress<T> calls a callback method for each message in the thread it was created in :
record FileProgress(string Name, int Index, int Total);
//This will run in the UI thread
void UpdateProgress(FileProgress fp)
{
...
}
private async Task OnRun()
{
//pg is created in the UI thread
var pg=new Progress<FileProgress>(UpdateProgress);
await Task.Run(()=>DoSomethingForVeryLongTime(pg));
}
async Task DoSomethingForVeryLongTime(IProgress<FileProgress> progress)
{
for int(i=0;i<1000;i++)
{
...
//Return to the UI thread and update it
progress.Report(new FileProgress(fileName,i,1000);
}
}
Avoiding Task.Run
Task.Run may not be needed at all if the "long runinng" work is an asynchronous operation, like waiting for a database response, an HTTP call or any IO operations. In this case we can use the asynchronous version of the operation, and get back to the UI thread when the operation completes.
Let's say we need to make multiple HTTP calls which can take several seconds. We can use HttpClient.GetAsync for this :
private async Task OnRun()
{
await DoSomethingForVeryLongTime();
}
async Task DoSomethingForVeryLongTime()
{
using var connection=new SqlConnection(_connectionString);
foreach(var url in _urls)
{
var response=await _httpClient.GetStringAsync(url);
await connection.ExecuteAsync(#"insert MyTable(url,response) values (#url, #response)",
new { url,response });
UpdateProgressBar(url);
}
lblStatus.Text="Complete";
}
This example uses Dapper to avoid the typical database boilerplate code. Dapper will open and close a connection as needed, so we avoid having a connection open while retrieving HTTP responses.
I've followed the following example which works well.
https://developer.xamarin.com/guides/cross-platform/application_fundamentals/web_services/walkthrough_working_with_WCF/
The only issue is, the example uses button clicks to load data. Now i have two separate calls different functions, and i need one to wait for the other, for example:
So when i call function2 for example, i want to wait for function1 first.
_client.function1Async();
_client.function2Async();
I could put the function2 call inside the function1Completed handler, but i was looking to use async wait with it. When i use async task, i get an error saying cannot await a void. But the web service async function in the example is a void
If i had 6 calls that i wanted to run, it would become very messy.
void _client_function1Completed(object sender,UpdateOrdersByWardCompletedEventArgs e
{
}
void _client_function2Completed(object sender,UpdateOrdersByWardCompletedEventArgs e
{
}
Hope this makes sense.
You could Task.ContinueWith
ContinueWith creates a continuation that executes asynchronously when task 1 completes.
var task1 = Task.Factory.StartNew( () => { func1(); } );
Task task2 = task1 .ContinueWith( (i) => { func2(); } );
Not sure if I understood well what you are trying to achieve, but I guess you can try something like this:
Given some lengthy (and blocking) methods:
public void func1()
{
Console.WriteLine("func1");
System.Threading.Thread.Sleep(5000);
}
public void func2()
{
Console.WriteLine("func2");
System.Threading.Thread.Sleep(5000);
}
You could add the ability to run the lengthy stuff asynchronously by doing this:
public async Task function1Async()
{
await Task.Run(() => {
func1();
});
}
public async Task function1Async()
{
await Task.Run(() => {
func2();
});
}
Now you can choose to run 'func1' and 'func2' either asynchronously or synchronously, for example:
function1Async().Wait(); // will block
function2Async(); // will run asynchronously
So, for your particular case, given that you already have the two async methods, I guess that all you need to do is to call them as shown above.
I'm programming an API for my software, which has a lot of interfaces and my software just inherits them.
I want the API users to have the possibility to do something after X milliseconds, something like this :
public void PerformAction(Action action, int delay)
{
Task.Run(async delegate
{
await Task.Delay(delai);
Form.BeginInvoke(action);
// I invoke on the Form because I think its better that the action executes in my main thread, which is the same as my form's thread
});
}
Now i know that the Task is like a new Thread, I just want to know, is this bad for my software? Is there any other possible better way?
The method will get executed a lot, so I don't know whether this approach is good or bad
You should not be creating a new Task for this, you can instead make the method a Task, something like this:
public async Task PerformAction(Action action, int delay)
{
await Task.Delay(delay);
action(); //this way you don't have to invoke the UI thread since you are already on it
}
And then simply use it like this:
public async void Butto1_Click(object sender, EventArgs e)
{
await PerformAction(() => MessageBox.Show("Hello world"), 500);
}
public async Task PerformAction(Action action, int delay)
{
await Task.Delay(delay);
action();
}
I'm new to c# async await mechanism. I read some articles about async all the way (http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html). I have an example below, could you please let me know if the first Initialize method will cause dead lock and why? Thank you in advance.
public class Test {
public async Task DoSomeWorkAsync() {
await DoSomeWork1Async();
}
// This method is mixed with Wait and async await, will this cause lead lock?
public void Initialize() {
Task.Run(() => DoSomeWorkAsync()).Wait();
}
// This method is following async all the way
public async Task InitializeAsync() {
await DoSomeWorkAsync();
}
}
// Update: Here is the context where two Initialize methods are called
public class TestForm : Form {
// Load Form UI
public async void OnLoad() {
var test = new Test();
test.Initialize();
await test.InitializeAsync();
}
}
No, this will not deadlock because you're blocking on a task that's being executed by a ThreadPool thread with no SynchronizationContext. Since it isn't running on the UI thread there's nothing stopping that task from completing and so there's no deadlock.
If this was your code, it will have deadlocked:
public void Initialize()
{
DoSomeWorkAsync().Wait();
}
This is still not a good reason to block though, you should use async-await all they way up.
I have a class with an async method:
public static async Task GetData() { ... }
In the app framework I am using I need to start that process and forget about it when the app starts:
protected override void OnStart()
{
await MyService.GetData();
}
I can't make OnStart async. How do I start it in a background task and forget about it?
I can't make OnStart Async. How do I start it in a background task and
forget about it?
Why not? Nothing prevents you from making it async. The async modifier doesn't affect the CLR method signature, i.e., you can override a void method and make it async:
abstract class AppBase
{
protected abstract void OnStart();
}
class App: AppBase
{
public static async Task GetData() { await Task.Delay(1); }
protected override async void OnStart()
{
await GetData();
}
}
This way, at least you'll see an exception if GetData throws, unlike what the other answer suggests.
Make sure you understand how async void methods and Task error handling work in general, this material may be helpful.
Some other problems with Task.Run( () => MyService.GetData() ):
as GetData is already asynchronous, there's very little sense in wrapping it with Task.Run. It's usually only done in a client-side UI app and only if GetData has a long-running synchronous part (before it hits its 1st await). Otherwise, you might as well just call GetData() without Task.Run and without await (which also would be a bad idea: in either case, you'd be doing a fire-and-forget call without observing possible exceptions).
Task.Run will start GetData on a random pool thread without synchronization content, which may be a problem for either a UI app or an ASP.NET app.
If you want to fire this async operation and forget about it all you need to do is invoke the method without awaiting the returned task:
protected override void OnStart()
{
MyService.GetDataAsync();
}
However, since you're not observing the task you would never know if it completed successfully.
You should either keep a reference to the task and await it in a later time:
public Task _dataTask;
protected override void OnStart()
{
_dataTask = MyService.GetDataAsync();
}
public Task AwaitInitializationAsync()
{
return _dataTask;
}
Or add a continuation handling any exceptions:
protected override void OnStart()
{
MyService.GetDataAsync().ContinueWith(t =>
{
try
{
t.Wait();
}
catch (Exception e)
{
// handle exceptions
}
});
}
You shouldn't use Task.Run as Noseratio explained, however using async void is much worse since an exception in an async void method (which isn't a UI event handler) would tear down the entire process*.
You can try to make the method async void while making sure there won't be any exceptions thrown inside it with a try-catch block:
protected override async void OnStart()
{
try
{
await GetData();
}
catch (Exception e)
{
// handle e.
}
}
But I would still recommend against it since even the chance of a complete crash is dangerous.
*You can get around that by registering an even handler for AppDomain.CurrentDomain.UnhandledException but this should be a last resort, not a best practice