I'm trying to run an "async" method from an ordinary method:
public string Prop
{
get { return _prop; }
set
{
_prop = value;
RaisePropertyChanged();
}
}
private async Task<string> GetSomething()
{
return await new Task<string>( () => {
Thread.Sleep(2000);
return "hello world";
});
}
public void Activate()
{
GetSomething.ContinueWith(task => Prop = task.Result).Start();
// ^ exception here
}
The exception thrown is:
Start may not be called on a continuation task.
What does that mean, anyway? How can I simply run my async method on a background thread, dispatch the result back to the UI thread?
Edit
Also tried Task.Wait, but the waiting never ends:
public void Activate()
{
Task.Factory.StartNew<string>( () => {
var task = GetSomething();
task.Wait();
// ^ stuck here
return task.Result;
}).ContinueWith(task => {
Prop = task.Result;
}, TaskScheduler.FromCurrentSynchronizationContext());
GetSomething.ContinueWith(task => Prop = task.Result).Start();
}
To fix your example specifically:
public void Activate()
{
Task.Factory.StartNew(() =>
{
//executes in thread pool.
return GetSomething(); // returns a Task.
}) // returns a Task<Task>.
.Unwrap() // "unwraps" the outer task, returning a proxy
// for the inner one returned by GetSomething().
.ContinueWith(task =>
{
// executes in UI thread.
Prop = task.Result;
}, TaskScheduler.FromCurrentSynchronizationContext());
}
This will work, but it's old-school.
The modern way to run something on a background thread and dispatch back to UI thread is to use Task.Run(), async, and await:
async void Activate()
{
Prop = await Task.Run(() => GetSomething());
}
Task.Run will start something in a thread pool thread. When you await something, it automatically comes back in on the execution context which started it. In this case, your UI thread.
You should generally never need to call Start(). Prefer async methods, Task.Run, and Task.Factory.StartNew -- all of which start the tasks automatically. Continuations created with await or ContinueWith are also started automatically when their parent completes.
WARNING about using FromCurrentSynchronizationContext:
Ok, Cory knows how to make me rewrite answer:).
So the main culprit is actually the FromCurrentSynchronizationContext!
Any time StartNew or ContinueWith runs on this kind scheduler, it runs on the UI Thread. One may think:
OK, let's start subsequent operations on UI, change some controls, spawn some operations. But from now TaskScheduler.Current is not null and if any control has some events, that spawn some StartNew expecting to be running on ThreadPool, then from there it goes wrong. UI aps are usually complex, unease to maintain certainty, that nothing will call another StartNew operation, simple example here:
public partial class Form1 : Form
{
public static int Counter;
public static int Cnt => Interlocked.Increment(ref Counter);
private readonly TextBox _txt = new TextBox();
public static void WriteTrace(string from) => Trace.WriteLine($"{Cnt}:{from}:{Thread.CurrentThread.Name ?? "ThreadPool"}");
public Form1()
{
InitializeComponent();
Thread.CurrentThread.Name = "ThreadUI!";
//this seems to be so nice :)
_txt.TextChanged += (sender, args) => { TestB(); };
WriteTrace("Form1"); TestA(); WriteTrace("Form1");
}
private void TestA()
{
WriteTrace("TestA.Begin");
Task.Factory.StartNew(() => WriteTrace("TestA.StartNew"))
.ContinueWith(t =>
{
WriteTrace("TestA.ContinuWith");
_txt.Text = #"TestA has completed!";
}, TaskScheduler.FromCurrentSynchronizationContext());
WriteTrace("TestA.End");
}
private void TestB()
{
WriteTrace("TestB.Begin");
Task.Factory.StartNew(() => WriteTrace("TestB.StartNew - expected ThreadPool"))
.ContinueWith(t => WriteTrace("TestB.ContinueWith1 should be ThreadPool"))
.ContinueWith(t => WriteTrace("TestB.ContinueWith2"));
WriteTrace("TestB.End");
}
}
Form1:ThreadUI! - OK
TestA.Begin:ThreadUI! - OK
TestA.End:ThreadUI! - OK
Form1:ThreadUI! - OK
TestA.StartNew:ThreadPool - OK
TestA.ContinuWith:ThreadUI! - OK
TestB.Begin:ThreadUI! - OK
TestB.End:ThreadUI! - OK
TestB.StartNew - expected ThreadPool:ThreadUI! - COULD BE UNEXPECTED!
TestB.ContinueWith1 should be ThreadPool:ThreadUI! - COULD BE UNEXPECTED!
TestB.ContinueWith2:ThreadUI! - OK
Please notice, that tasks returned by:
async method,
Task.Fatory.StartNew,
Task.Run,
can not be started! They are already hot tasks...
Related
I have a big time-consuming task and I try to implement asynchronous methods in order to prevent the application from blocking. My code looks like this:
CancellationTokenSource _cts;
async void asyncMethod()
{
// ..................
_cts = new CancellationTokenSource();
var progress = new Progress<double>(value => pbCalculationProgress.Value = value);
try
{
_cts.CancelAfter(25000);
int count = await awaitMethod(_cts.Token, progress);
}
catch (OperationCanceledException ex)
{
// .......
}
finally
{
_cts.Dispose();
}
// ..................
}
async Task<int> awaitMethod(CancellationToken ct, IProgress<double> progress)
{
var task = Task.Run(() =>
{
ct.ThrowIfCancellationRequested();
sqlParser();
progress.Report(1);
return 0;
});
return await task;
}
void sqlParser()
{
string info = form1TxtBox.Text;
// ................
}
Also, the program throws an exception, because sqlParser() updates UI thread, when it retrieves the text from the form. The solution is to introduce Dispatcher method, which allows UI update. I keep the body of awaitMethod the same and simply put sqlParser() inside of the Dispatcher:
DispatcherOperation op = Dispatcher.BeginInvoke((Action)(() =>
{
sqlParser();
}));
Here happens something interesting: asyncMethod() even doesn't dare to call awaitMethod! However, if I put a breakpoint inside of sqlParser() and run debugger, then everything goes very smoothly.
Please, can somebody explain what I miss in my code? What kind of patch should i use to make Dispatcher work correctly? Or: how can I run my program without Dispatcher and without throwing UI-update exception?
The solution is to introduce Dispatcher method, which allows UI update.
That's never a good solution. Having background threads reaching directly into your UI is encouraging spaghetti code.
how can I run my program without Dispatcher and without throwing UI-update exception?
Think of your background thread code as its own separate component, completely separate from the UI. If your background code needs data from the UI, then have your UI code read it before the background code starts, and pass that data into the background code.
async void asyncMethod()
{
...
try
{
var data = myUiComponent.Text;
_cts.CancelAfter(25000);
int count = await awaitMethod(data, _cts.Token, progress);
}
...
}
async Task<int> awaitMethod(string data, CancellationToken ct, IProgress<double> progress)
{
var task = Task.Run(() =>
{
ct.ThrowIfCancellationRequested();
sqlParser(data);
progress.Report(1);
return 0;
});
return await task;
}
This code gives a compile time error in VS2015
Error CS0266 Cannot implicitly convert type 'System.Threading.Tasks.Task' to 'System.Threading.Tasks.Task<System.Threading.Tasks.Task>'. An explicit conversion exists (are you missing a cast?)
UPDATE 1: extended code after a Task instead of Task< Task > was suggested.
int i = 0;
Task<int> test = Task.Run( () => {
return i;
} );
i = test.Result;
Task t = Task.Run( () => { } );
Task<Task> test2 = Task.Run( () => {
return t;
} );
t = test2.Result;
What am I doing wrong?
UPDATE 2:
This code gives a warning (and I want no warnings and no suppress pragmas)
Warning CS1998 This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
int i = 0;
Task<int> test = Task.Run( () => {
return i;
} );
i = test.Result;
Task t = Task.Run( () => { } );
Task<Task> test2 = Task.Run( async () => {
return t;
} );
t = test2.Result;
UPDATE 3:
To all people insisting on Task test2.
StartAndReturnSecondTaskAsync must return the second task (executing longOperation2)
StartAndReturnSecondTaskAsync must be async, i.e. UI must not block for the duration of longOperation1
public static async Task<Task> StartAndReturnSecondTaskAsync() {
Task t = await Task.Run( () => {
return StartAndReturnSecondTask();
} );
return t;
}
public static Task StartAndReturnSecondTask() {
var importantData = longOperation1();
return Task.Run( () => {
longOperation2( importantData );
} );
}
...
Task second = await StartAndReturnSecondTaskAsync();
It's an extremely common but to use Task.Run to perform some asychronous operation, and if using the older method StartNew it would do what you're expecting, which is to schedule a thread pool thread to start the asynchronous operation, and tell you when that asynchronous operation has finished being started.
This is, however, basically never what people actually want. They want to know when the asynchronous operation called in Task.RUn finishes. Because of this, Task.Run will unwrap any Task<Task> that would be returned, so that what you're really seeing is the innerTask`.
If you really do just want to have a thread pool thread start the task, and just know when it has finished being started, then you can use Task.Factory.StartNew which does not unwrap the Task<Task> on your behalf.
Task<Task> are quite common and often a problem (if we erroneously wait/await wrong, outer task):
int i = 0;
Task<int> test = Task.Run(() => {
return i;
});
Task t = Task.Run(() => {
});
// please, notice "async"
Task<Task> test2 = Task.Run(async () => { // <- async: let insist on Task<Task>...
return t;
});
There's even an extension method for Task<Task>
Task backToTask = test2.Unwrap();
In your case you want
Task test2 = Task.Run(() => {
return t;
});
Since Task.Run calls Unwrap() for you
A simple solution without getting into much details:
The code that would work would be:
int i = 0;
Task<int> test = Task.Run(() =>
{
return i;
});
Task t = Task.Run(() => { });
Task test2 = Task.Run(() =>
{
return t;
});
If you go with other possible approaches that use await, You would need to make the context async, like:
public async Task DoesTheThreadedOperations()
{
// Your code in question and other code
}
As per your Update 3
public static async Task StartAndReturnSecondTaskAsync()
{
await Task.Run(() =>
{
return StartAndReturnSecondTask();
});
}
public static Task StartAndReturnSecondTask()
{
System.Threading.Thread.Sleep(5000);
return Task.Run(() =>
{
System.Threading.Thread.Sleep(10000);
});
}
I have used sleep to imitate your long operations. I hope you don't necessarily want to use Task<Task>. This should give you enough thrust to attack your scenario. You can further improve it to get your exact results by making these two operations two different threads and pass the results from one to other, await the one you want and run and leave the other longer task running without await. That is, call both methods from your main method, one awaited and other not.
I need to make UI thread wait until a task array completes execution.The problem with below code is that - the tasks inturn invoke UI thread to write into textbox. How to fix this?
public partial class FormConsole : Form
{
public FormConsole()
{
InitializeComponent();
}
void txtSayHello_Click(object sender, EventArgs e)
{
Class1 objclss = new Class1();
objclss.formConsole = this;
Task[] taa = new Task[4];
taa[0] = new Task(() => objclss.DoSomeThigs("Hello world"));
taa[1] = new Task(() => objclss.DoSomeThigs("Hello world1"));
taa[2] = new Task(() => objclss.DoSomeThigs("Hello world2"));
taa[3] = new Task(() => objclss.DoSomeThigs("Hello world3"));
foreach(Task task in taa)
{
task.Start();
}
Task.WhenAll(taa);
this.txtConsole.AppendText("All threads complete");
}
delegate void doStuffDelegate(string value);
public void doStuff(string value)
{
if (System.Windows.Forms.Form.ActiveForm.InvokeRequired && IsHandleCreated)
{
BeginInvoke(new doStuffDelegate(doStuff), value);
}
else
txtConsole.AppendText(value);
}
}
public class Class1
{
public FormConsole formConsole;
public void DoSomeThigs(string sampleText)
{
formConsole.doStuff(sampleText);
}
}
o/p now : Console Redirection TestAll threads completeHello worldHello world1Hello world2Hello world3
o/p I want : Console Redirection TestHello worldHello world1Hello world2Hello world3All threads complete
What's the solution?
Task.WhenAll returns a task that completes when all tasks passed to it complete. You have to await this task, otherwise the method will continue executing.
async void txtSayHello_Click(object sender, EventArgs e)
{
...
await Task.WhenAll(taa);
...
}
There is a blocking version of this method - Task.WaitAll. It will block the current thread until all tasks are done, but it's not a good idea to block the UI thread.
Also, the preferred way to start a task on a thread pool thread is to use Task.Run.
Task.WhenAll returns a Task representing the completion of all these tasks in the enumerable. You need to await that task as the method doesn't block the thread.
Turn txtSayHello_Click into an async void (which should only be used for event handlers) method and await the task returned from Task.WhenAll:
async void txtSayHello_Click(object sender, EventArgs e)
{
// ...
await Task.WhenAll(taa);
// ...
}
Moreover, you should almost always avoid using the Task constructor. You should use Task.Factory.StartNew with TaskScheduler.FromSynchronizationContext if you need the task to run on the UI thread (that depends on what you actually do with FormConsole) or Task.Run if you don't. Meaning:
taa[0] = Task.Factory.StartNew(() => objclss.DoSomeThigs("Hello world"), CancellationToken.None, TaskCreationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
Or:
taa[0] = Task.Run(() => objclss.DoSomeThigs("Hello world"));
You're most likely confusing WhenAll() with WaitAll().
As already suggested you can use async with await or you can simply use :
A) Task.WhenAll(taa).Wait();
B) Task.WaitAll(taa);
But in your case this will block UI thread. So it's better to put rest of the code to Continuation Task and invoke UI operations with Control.Invoke() :
Task.WhenAll(taa).ContinueWith(t =>
{
this.Invoke(() => this.txtConsole.AppendText("All threads complete"));
});
I have to create a method, that similar to ContinueWith(), but will execute continuation in main thread, after main Task.
How can I do that?
I could endlessly checking the state of Task in my method, and when it finishes start continuation, but I think it couldn`t work in such way:
Task<DayOfWeek> taskA = new Task<DayOfWeek>(() => DateTime.Today.DayOfWeek);
Task<string> continuation = taskA.OurMethod((antecedent) =>
{
return String.Format("Today is {0}.", antecedent.Result);
});
// Because we endlessly checking state of main Task
// Code below will never execute
taskA.Start();
So what I could do here?
Try passing around the "main" thread's Dispatcher. Example:
Task.Factory.StartNew(()=>
{
// blah
}
.ContinueWith(task=>
{
Application.Current.Dispatcher.BeginInvoke(new Action(()=>
{
// yay, on the UI thread...
}
}
Assuming that the "main" thread is UI thread. If it's not, then grab that thread's dispatcher after you make it. Use that dispatcher instead of Application.Current's (i.e. CurrentDispatcher).
You can create an ExtensionMethod for a process like this. Here is an example implementation
static class ExtensionMethods
{
public static Task ContinueOnUI(this Task task, Action continuation)
{
return task.ContinueWith((arg) =>
{
Dispatcher.CurrentDispatcher.Invoke(continuation);
});
}
}
Consume it like this.
Task run = new Task(() =>
{
Debug.WriteLine("Testing");
});
run.ContinueOnUI(() =>
{
Notify += "\nExecuted On UI"; // Notify is bound on a UI control
});
run.Start();
public async override void InitData()
{
_domainModel = new DomainModel()
ProgressIndicatorViewModel.Start();
_State = Getstate();
await _domainModel.Load(_State, ProgressIndicatorViewModel); //returns a task
ImageSelectionViewModel.UpdateState(_State); //returns void not a task!
ProgressIndicatorViewModel.Stop();
DispatcherHelper.UIDispatcher.Invoke(() => ImageSelectionViewModel.RefreshImages(_imageList));
}
i would like to make the two methods (1.domaminModel.Load(), 2. UpdateState()) to run on the same thread one after the other. not on the UI thread.
how can i do this?
i would like to make the two methods (1.domaminModel.Load(), 2.
UpdateState()) to run on the same thread one after the other. not on
the UI thread.
Updated, if you want only _domainModel.Load and ImageSelectionViewModel.UpdateState to run on a separate non-UI thread, then just do this:
public async override void InitData()
{
_domainModel = new DomainModel()
ProgressIndicatorViewModel.Start();
_State = Getstate();
await Task.Run(async () =>
{
await _domainModel.Load(_State, ProgressIndicatorViewModel))
ImageSelectionViewModel.UpdateState(_State); //returns void not a task!
});
ProgressIndicatorViewModel.Stop();
ImageSelectionViewModel.RefreshImages(_imageList);
}
Note you do not need DispatcherHelper.UIDispatcher.Invoke() wrapper then.
If you want the rest of InitData after _domainModel.Load to run on a separate thread:
public async override void InitData()
{
_domainModel = new DomainModel()
ProgressIndicatorViewModel.Start();
_State = Getstate();
await Task.Run(() => _domainModel.Load(_State,
ProgressIndicatorViewModel)).ConfigureAwait(false);
ImageSelectionViewModel.UpdateState(_State); //returns void not a task!
DispatcherHelper.UIDispatcher.Invoke(() =>
{
ProgressIndicatorViewModel.Stop();
ImageSelectionViewModel.RefreshImages(_imageList)
});
}
Note that Task.Run will automatically unwrap the nested task (of Task<Task<T>>) for your here. Also, you'd probably need to move ProgressIndicatorViewModel.Stop() inside Dispatcher.Invoke.
Depending on what's inside _domainModel.Load, you may not even need Task.Run:
await _domainModel.Load(_State,
ProgressIndicatorViewModel).ConfigureAwait(false);
One a side note, you should probably handle exceptions inside your async void InitData method. You won't be able to handle them outside it.
Consider following codes:
public async void Sample()
{
DoOne();
await DoTwo();
DoThree();
Dispather.BeginInvoke(() => DoFour());
}
DoOne Will not executed in UI Thread (!), its thread will be a thread that is a caller of method Sample() named Caller Thread
In most cases in client side the Caller thread is UI Thread, because most codes are invoked by user actions (such as mouse click), but it's not a fixed behavior.
DoTwo will be executed in a separated thread, it's clear that it will not be executed in caller thread.
DoThree will be executed in a Caller Thread
and DoFour will be executed at UI Thread, it does not matter that what's a caller thread.
So the comment of #usr is totally wrong.
To achieve your goal change your code as following:
public async override void InitData()
{
_domainModel = new DomainModel()
ProgressIndicatorViewModel.Start();
_State = Getstate();
await Task.Factory.StartNew(() => {
_domainModel.Load(_State, ProgressIndicatorViewModel).ContinueWith(() => {
ImageSelectionViewModel.UpdateState(_State); });
};
ProgressIndicatorViewModel.Stop();
DispatcherHelper.UIDispatcher.Invoke(() => ImageSelectionViewModel.RefreshImages(_imageList));
}