Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AsyncAwait causes unexpected method behavior, Methods runs in wrong thread if called from constructor

I'm trying to do some time consuming actions without freezing the GUI Thread. The UpdateSomething Method is called in two places once in the constructor of my ViewModel and once on button click (RelayCommand). The Method is executed in a WorkerThread if the method is called via RelayCommand, but runs in the MainThread (GUI) when the method call comes from the constructor.

What causes this strange behavior? I double check a few times via IntelliTrace.

This is the method in question:

private async void UpdateSomething()
{
    var item = await Task.Factory.StartNew(() =>this.DoSomething("I should run async"));
    this.TestItem = item;
}

I'm using WPF and .Net 4.5

like image 711
Joel Avatar asked Dec 31 '25 12:12

Joel


2 Answers

For the case where the Tasks action runs on the main thread, the most likely cause is that the method UpdateSomething is being called from within another Task (a Task that was scheduled to run on the main thread). In that case, the TaskScheduler.Current is the main thread TaskScheduler not the TaskScheduler.Default which queues work to the thread pool.

Task.Factory.StartNew defaults to using TaskScheduler.Current (you can change what it uses by calling the appropriate override), while Task.Run uses TaskScheduler.Default.

The statement that Task.Factory.StartNew doesn't play will with async/await is not correct, it's just that some of the defaults are probably not what you want for the common case (this is part of whyTask.Run was introduced).

See:

  • http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx
  • Why is TaskScheduler.Current the default TaskScheduler?
like image 130
Matt Smith Avatar answered Jan 02 '26 02:01

Matt Smith


I ran into the same problem a while ago. I stuck up a little post about it here:

Today I had a major hair pulling moment. I was using a await/async on a block of code wrapped in a new task. No matter what I did it would just start the Task but then not wait for the result.

After much frustration I worked out that using await Task.Factory.StartNew doesn't play well with await.

In the end I simply changed it to Task.Run what was then worked fine.

Basically you need to use Task.Run instead because await doesn't play nicely with Task.Factory.StartNew

like image 23
pingoo Avatar answered Jan 02 '26 03:01

pingoo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!