Here is the code:
static async Task Main(string[] args)
{
var t = new Task(async () => await AsyncTest());
t.Start();
t.Wait();
Console.WriteLine("Main finished");
}
private static async Task AsyncTest()
{
Thread.Sleep(2000);
await Task.Delay(2000);
Console.WriteLine("Method finished");
}
My expectation is that t.Wait() will actually wait for AsyncTest method completion and output will be:
Method finished
Main finished
In reality output has only Main finished. Wait() is completed right at the moment when you hit await Task.Delay(2000) inside AsyncTest. The same happens if you replace t.Wait() with await t / await Task.WhenAll(t) / Task.WaitAll(t).
The solution is to rewrite method to synchronous implementation or call Wait() directly on AsyncTest(). However, the question is why does it work in such strange way?
P.S. It's a simplified version of code. I was trying to achieve deferred task execution. In reality Task object is created by one part of program and then later is executed by another part after some specific condition.
UPD: Rewriting var t = new Task(async () => await AsyncTest()) to var t = new Task(()=> AsyncTest().Wait()) also fixes the problem. Though I still don't quite understand why Task doesn't work correctly with async/await inside delegate.
I still don't quite understand why Task doesn't work correctly with async/await inside delegate.
Because the Task constructor is only used for creating Delegate Tasks - i.e., tasks that represent synchronous code to be run. Since the code is synchronous, your async lambda is being treated as an async void lambda, which means the Task instance won't asynchronously wait for AsyncTest to complete.
More to the point, the Task constructor should never, ever be used in any code, anywhere, for any reason. It has literally zero valid use cases.
A good replacement for Task.Task is Task.Run, which does understand async lambdas.
In my real program Task has deferred execution. Task object is created in one place, and then later after specific condition executed by another part of program.
In that case, use an asynchronous delegate. Specifically, Func<Task>.
static async Task Main(string[] args)
{
Func<Task> func = AsyncTest;
// Later, when we're ready to run.
await func();
Console.WriteLine("Main finished");
}
private static async Task AsyncTest()
{
Thread.Sleep(2000);
await Task.Delay(2000);
Console.WriteLine("Method finished");
}
A quote from #JonSkeet:
Your async method just returns void, which means there's no simple way
of anything waiting for it to complete. (You should almost always
avoid using async void methods. They're really only available for the
sake of subscribing to events.)
So look at this line of your code:
var t = new Task(async () => await AsyncTest());
Look at the signature of Task constructors:
public Task(Action action);
public Task(Action action, CancellationToken cancellationToken);
public Task(Action action, TaskCreationOptions creationOptions);
public Task(Action<object> action, object state);
public Task(Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions);
public Task(Action<object> action, object state, CancellationToken cancellationToken);
public Task(Action<object> action, object state, TaskCreationOptions creationOptions);
public Task(Action<object> action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions);
All of them are Actions and as you know Action has void return type.
static async Task Main(string[] args)
{
// best way to do it
await AsyncTest();
Console.WriteLine("Main finished");
}
private static async Task AsyncTest()
{
// Don't use thread sleep, await task delay is fine
// Thread.Sleep(2000);
await Task.Delay(2000);
Console.WriteLine("Method finished");
}
check this
public static async Task Main(string[] args)
{
var t = Task.Factory.StartNew(async () => await AsyncTest());
//t.Start();
t.Result.Wait();
t.Wait();
Console.WriteLine("Main finished");
}
private static async Task AsyncTest()
{
//Thread.Sleep(2000);
await Task.Delay(2000);
Console.WriteLine("Method finished");
}
and this link
Don't use var task = new Task(...); task.Start();, use just Task.Run instead.
In 1st case constructor Task(Action action) is used so you actually doesn't await async method actually. If you inspect real C# without asyn-await syntax sugar you will see AsyncVoidMethodBuilder. In case of Task.Run you use Task.Run(Func<Task> func) so you receive "real" tasks.
So if you want to use constructor you should use approach from comments: new Task<Task>.
Related
Regarding the right worker method signature I need to understand the following:
is there a point in returning Task instead of void for Worker method (if going sync)?
Should I really wait (call Wait()) on the Worker method (if going sync)?
what should be the return value of Worker method when marked as returning Task object (both if going sync/async)?
what signature and body of Worker method should be, given the work it completes is long-running CPU/IO-bound work? Should I follow this recommendation (if going mixed/async)?
Note
Despite the cpu-bound code, there's a choice to call async versions of io-bound methods (sql queries). So it may be all sync or partially async. As for the nature of code in the Worker method.
public class LoopingService
{
private CancellationTokenSource cts;
// ..
void Worker(CancellationToken cancellationToken)
{
while(!cancellationToken.IsCancellationRequested)
{
// mixed, CPU/IO-bound code
try {
// sql query (can be called either as sync/async)
var lastId = documentService.GetLastDocument().Id;
// get next document from a public resource (third-party code, sync)
// can be moved to a web api
var document = thirdPartyDocumentService.GetNextDocument(lastId);
// apply different processors in parallel
var tasksList = new List<Task>();
foreach(var processor in documentService.Processors) {
// each processor checks if it's applicable
// which may include xml-parsing, additional db calls, regexes
// if it's applicable then document data is inserted into the db
var task = new Task(() => processor.Process(document));
tasksList.Add(task);
task.Start();
}
// or
// var tasksList = documentService.ProcessParallel(document);
Task.WaitAll(tasksList.ToArray(), cancellationToken);
}
catch(Exception ex) {
logger.log(ex);
}
}
}
public void Start()
{
this.cts = new CancellationTokenSource();
Task.Run(() => this.Worker(cts.Token));
}
public void Stop()
{
this.cts.Cancel();
this.cts.Dispose();
}
}
is there a point in returning Task instead of void for Worker method?
If Worker is a truly asynchronous method it should return a Task for you to be able to await it. If it's just a synchronous method runnning on a background thread there is no point of changing the return type from void provided that the method is not supposed to return anything.
what should be the return value of Worker method when marked as returning Task object?
Nothing. Provided that the method is asynchronous and marked as async with a return type of Task, it shouldn't return any value:
async Task Worker(CancellationToken cancellationToken) { ... }
Note that there is no point of defining the method as async unless you actually use the await keyword in it.
what signature and body of Worker method should be given the work it completes is long-running CPU/IO-bound work? Should I follow this recommendation?
Yes, probably. If you for some reason are doing both asynchronous and synchronous (CPU-bound) work in the same method, you should prefer to using an asynchronous signature but not wrap the synchronous stuff in Task.Run. Then your service would look something like this:
public class LoopingService
{
private CancellationTokenSource cts;
async Task Worker(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
await ...
}
}
public async Task Start()
{
this.cts = new CancellationTokenSource();
await this.Worker(cts.Token).ConfigureAwait(false);
}
public void Stop()
{
this.cts.Cancel();
this.cts.Dispose();
}
}
Ideally your method should be either asynchronous or CPU-bound but not both though.
Why does a method returning a Task does not get executed when returning it's instance. I thought this must happen, because awaiting the method/delegate would
put it into some queue and later execute the resulting task.
So why does this Task never gets executed when calling Do()?
public void Do()
{
SomeTask().Wait()
}
public async Task SomeTask()
{
return new Task(() => { Console.WriteLine("Hello World!") });
}
EDIT
Or do I alwas need await Task.Run(...)?
Thank you very much!
You're creating a Task but never starting it, so it's impossible for it to complete.
Use Task.Run to return a "hot" (started) Task instead:
return Task.Run(() => { Console.WriteLine("Hello World!") });
Also, async keyword is unnecessary as you're not awaiting the created task.
I've this method
public void Execute(Action action)
{
try
{
action();
}
finally
{
}
}
and I need to convert it to an async method call like this one
public async Task ExecuteAsync(Action action)
{
try
{
await action();
}
finally
{
}
}
The problem with the code above is that the compiler issue the following error
The 'await' operator can only be used within an async lambda
expression. Consider marking this lambda expression with the 'async'
modifier.
If you want to await on a delegate, it has to be of type Func<Task> or Func<Task<T>>. An Action is equivalent into a void Action() named method. You can't await on void, yet you can await Task Func() or Task<T> Func:
public async Task ExecuteAsync(Func<Task> func)
{
try
{
await func();
}
finally
{
}
}
If this can't be done, it means that internally the method isn't truly asynchronous, and what you actually want to do is execute the synchronous delegate on a thread-pool thread, which is a different matter, and isn't really executing something asynchronously. In that case, wrapping the call with Task.Run will suffice.
Try this:
public async void ExecuteAsync(Action action)
{
await Task.Run(action);
}
Using Task.Run()creates an awaitable by running your action on a different task.
And also bear in mind that handling exceptions on "awaitables" does not work as intended.
Better wrap that action() call in a try catch an do Task.Run() on that wrapper.
Let's simplify your starting point down to:
public void Execute(Action action)
{
action();
}
Because you say the finally isn't important.
Valid but pointless:
public async Task ExecuteAsync(Action action)
{
action();
}
This will be pretty much the same as doing:
public Task ExecuteAsync(Action action)
{
action();
return Task.FromResult(0);
}
That is, it'll do what the non-async was doing, and then return a "completed" Task so nothing is gained. It's worth noting though as it's often a valid part-way-point in moving from non-async to async.
Better:
public async Task ExecuteAsync(Action action)
{
await Task.Run(() => action());
}
Which in this case, because it's a single void-returning call can be simplified to:
public async Task ExecuteAsync(Action action)
{
await Task.Run(action);
}
Whether this is worth doing or not is another matter. This releases the current thread from being used, but transfers to another thread to do the work. If we're just going to await the result of this when it's called then we might as well just call the non-async version and be done with it. If however we're doing WaitAll in the caller, or something else that hence benefits from this, then it could indeed be useful.
Potentially much better though is:
public async Task ExecuteAsync(Action action)
{
await actionAsync();
}
Here there's an Async version of the method we are calling, so we change to make use of that. Now, that could be just the same as the above if actionAsync just spins up a thread or uses the thread pool. If however actionAsync does something using asynchronous I/O then there's a much bigger benefit to this.
Note that in this case we could have just tail-called the Task we get:
public Task ExecuteAsync(Action action)
{
return actionAsync();
}
However, that wouldn't be the same if we needed something done after an await within our method. E.g.:
public void Execute(Action action)
{
action();
otherAction();
}
Would have to become:
public async Task Exectute(Action action)
{
await actionAsync();
await otherActionAsync();
}
Or if otherAction had no async version:
public async Task Exectute(Action action)
{
await actionAsync();
otherAction();
}
This is how my code is setup. However I am getting an exception when updating myUIElement in Method2.
"the calling thread cannot access this object because a different
thread owns it.
Should anything after await always be called on UI thread? What am I doing wrong here?
private async void Method1()
{
// I want to wait until Method2 is completed before doing anything else in Method1
await Task.Factory.StartNew(() => Method2());
}
private async void Method2()
{
// Reading few things from configuration etc
await Task.Factory.StartNew(() => SomeAPILoadDataFromSomewhere());
myUIElement.Text = "something useful has happened";
}
}
You shouldn't be using StartNew when you don't actually want the code in question to run in a non-UI thread. Just remove it entirely.
Also note that you should only have async void methods as top level event handlers. Any async method that you intend to await should return a Task.
You should also generally be using Task.Run instead of StartNew where possible.
//This should return a Task and not void if it is used by another asynchronous method
private async void Method1()
{
await Method2();
DoSomethingElse();
}
private async Task Method2()
{
await Task.Run(() => SomeAPILoadDataFromSomewhere());
myUIElement.Text = "something useful has happened";
}
seems that all async examples end up calling a .net async method,
is it possible to create a custom async method that is not calling a .net async method ?
this is where I got so far:
[Test]
public void Test()
{
TestAsync();
}
public async void TestAsync()
{
await DoStuffAsync(1);
Task.Run(() => DoStuffAsync(73));
await Task.WhenAll(DoStuffAsync(2), DoStuffAsync(3));
}
public async Task DoStuffAsync(int n)
{
Thread.Sleep(1000);
Console.WriteLine("done stuff " + n);
}
the only problem with this is that VS says that async keyword in DoStuffAsync is useless (cuz there's no await), but I don't need await, I just need the possibility to await this method
The primary purpose of the async keyword is to enable the await keyword. An async method without an await doesn't make much sense, hence the compiler warning.
You can implement a Task-returning method without async, as such:
public Task DoStuffAsync(int n)
{
return Task.Delay(1000);
}
If you want to create your own Tasks from scratch, use Task.Run or TaskCompletionSource<T> (or one of its shortcuts such as Task.FromResult or TaskFactory.FromAsync).
P.S. You generally want to avoid async void; use async Task instead.
public async void TestAsync()
{
await DoStuffAsync(1);
await DoStuffAsync(73);
await Task.WhenAll(DoStuffAsync(2), DoStuffAsync(3));
}
public async Task DoStuffAsync(int n)
{
await Task.Delay(1000);
Console.WriteLine("done stuff " + n);
}