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.
Related
In contrast to Task.Wait() or Task.Result, await’ing a Task in C# 5 prevents the thread which executes the wait from lying fallow. Instead, the method using the await keyword needs to be async so that the call of await just makes the method to return a new task which represents the execution of the async method.
But when the await’ed Task completes before the async method has received CPU time again, the await recognizes the Task as finished and thus the async method will return the Task object only at a later time. In some cases this would be later than acceptable because it probably is a common mistake that a developer assumes the await’ing always defers the subsequent statements in his async method.
The mistaken async method’s structure could look like the following:
async Task doSthAsync()
{
var a = await getSthAsync();
// perform a long operation
}
Then sometimes doSthAsync() will return the Task only after a long time.
I know it should rather be written like this:
async Task doSthAsync()
{
var a = await getSthAsync();
await Task.Run(() =>
{
// perform a long operation
};
}
... or that:
async Task doSthAsync()
{
var a = await getSthAsync();
await Task.Yield();
// perform a long operation
}
But I do not find the last two patterns pretty and want to prevent the mistake to occur. I am developing a framework which provides getSthAsync and the first structure shall be common. So getSthAsync should return an Awaitable which always yields like the YieldAwaitable returned by Task.Yield() does.
Unfortunately most features provided by the Task Parallel Library like Task.WhenAll(IEnumerable<Task> tasks) only operate on Tasks so the result of getSthAsync should be a Task.
So is it possible to return a Task which always yields?
First of all, the consumer of an async method shouldn't assume it will "yield" as that's nothing to do with it being async. If the consumer needs to make sure there's an offload to another thread they should use Task.Run to enforce that.
Second of all, I don't see how using Task.Run, or Task.Yield is problematic as it's used inside an async method which returns a Task and not a YieldAwaitable.
If you want to create a Task that behaves like YieldAwaitable you can just use Task.Yield inside an async method:
async Task Yield()
{
await Task.Yield();
}
Edit:
As was mentioned in the comments, this has a race condition where it may not always yield. This race condition is inherent with how Task and TaskAwaiter are implemented. To avoid that you can create your own Task and TaskAwaiter:
public class YieldTask : Task
{
public YieldTask() : base(() => {})
{
Start(TaskScheduler.Default);
}
public new TaskAwaiterWrapper GetAwaiter() => new TaskAwaiterWrapper(base.GetAwaiter());
}
public struct TaskAwaiterWrapper : INotifyCompletion
{
private TaskAwaiter _taskAwaiter;
public TaskAwaiterWrapper(TaskAwaiter taskAwaiter)
{
_taskAwaiter = taskAwaiter;
}
public bool IsCompleted => false;
public void OnCompleted(Action continuation) => _taskAwaiter.OnCompleted(continuation);
public void GetResult() => _taskAwaiter.GetResult();
}
This will create a task that always yields because IsCompleted always returns false. It can be used like this:
public static readonly YieldTask YieldTask = new YieldTask();
private static async Task MainAsync()
{
await YieldTask;
// something
}
Note: I highly discourage anyone from actually doing this kind of thing.
Here is a polished version of i3arnon's YieldTask:
public class YieldTask : Task
{
public YieldTask() : base(() => { },
TaskCreationOptions.RunContinuationsAsynchronously)
=> RunSynchronously();
public new YieldAwaitable.YieldAwaiter GetAwaiter()
=> default;
public new YieldAwaitable ConfigureAwait(bool continueOnCapturedContext)
{
if (!continueOnCapturedContext) throw new NotSupportedException();
return default;
}
}
The YieldTask is immediately completed upon creation, but its awaiter says otherwise. The GetAwaiter().IsCompleted always returns false. This mischief makes the await operator to trigger the desirable asynchronous switch, every time it awaits this task. Actually creating multiple YieldTask instances is redundant. A singleton would work just as well.
There is a problem with this approach though. The underlying methods of the Task class are not virtual, and hiding them with the new modifier means that polymorphism doesn't work. If you store a YieldTask instance to a Task variable, you'll get the default task behavior. This is a considerable drawback for my use case, but I can't see any solution around it.
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>.
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.
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";
}
I'd like to make a function async, so I simply add async like this:
public async static void something(){
}
You can see that its return-type is void. I just want this function to be called asynchronously without blocking, since return is void so no await is needed.
But Visual Studio 2012 just cannot compile this, it says that I miss await?
Could you please advise a sample that makes a function async without using await.
I think that maybe you misunderstand what async does. The warning is exactly right: if you mark your method async but don't use await anywhere, then your method won't be asynchronous. If you call it, all the code inside the method will execute synchronously.
Also, you should try to avoid using async void methods, they make handling exceptions difficult.
Change to
public async Task something(){
return await Task.Factory.StartNew(() => {
//TODO:
}
}
You do not have to wait for the Task returned ;)
so alternatively You can just use a task and remove both async and await and then you get:
public Task something(){
return Task.Factory.StartNew(() => {
//TODO:
}
}
Task is implict void, if you do not use the generic return type argument