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();
}
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.
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.
Suppose I have a method that awaits a Task. This method also returns a Task. For example:
public async virtual Task Save(String path)
{
if (NewWords.Any())
{
await FileManager.WriteDictionary(path, NewWords, true);
}
else await Task.Run(() => { });
}
Is the
else await Task.Run(() => { });
necessary here or am I free to leave it? Is there any difference if it is present/absent? Maybe there is some other approach to this I should take?
It's worse than unnecessary, as you're spinning up a thread to do nothing and then waiting until after its finished doing nothing.
The simplest way to do nothing, is to do nothing. In an async method the method will still have returned a Task, but that Task will be completed already, so something awaiting it further up will get straight onto the next thing it needs to do:
public async virtual Task Save(String path)
{
if (NewWords.Any())
{
await FileManager.WriteDictionary(path, NewWords, true);
}
}
(Also, it would be more in line with convention if SaveAsync and WriteDictionaryAsync were the method names here).
If not using async (and there's no need to here, but I understand it's an example) use Task.CompletedTask:
public virtual Task Save(String path)
{
if (NewWords.Any())
{
return FileManager.WriteDictionary(path, NewWords, true);
}
return Task.CompletedTask;
}
If you are coding against an earlier framework than 4.6 and therefore don't have CompletedTask available, then Task.Delay(0) is useful as Delay special cases the value 0 to return a cached completed task (in fact, the same one that CompletedTask returns):
public virtual Task Save(String path)
{
if (NewWords.Any())
{
return FileManager.WriteDictionary(path, NewWords, true);
}
return Task.Delay(0);
}
But the 4.6 way is clearer as to your intent, rather than depending on a quirk of implementation.
It's not neccesary. The async is only needed if at least one await is used. Everything inside the method is executed synchronously except for the await part.
Not return value optimization in the traditional sense, but I was wondering when you have a situation like this:
private async Task Method1()
{
await Method2();
}
private async Task Method2()
{
await Method3();
}
private async Task Method3()
{
//do something async
}
This could obviously be written more optimally:
private Task Method1()
{
return Method2();
}
private Task Method2()
{
return Method3();
}
private async Task Method3()
{
//do something async
}
I just wondered whether anyone knew if the (MS) compiler was clever enough not to generate state machines for Method1() and Method2() in the first instance?
No, the C# compiler doesn't optimize it and it should not. These are conceptually two different things, here is a similar question.
IMO, the major difference is in how exceptions are getting propogated into the caller of Method1 and Method2. I demo'ed this behavoir here.
In the first case (without the state machine), an exception will be immediately thrown on the caller's stack frame. If it is unhanded, the app may crash right away (unless there is another async method in the chain of calls on the same stack frame).
In the second case (with the state machine), an exception will remain dormant in the Task object returned to the caller, until it is observed via await task or task.Wait(), some time later. It may get observed on a completely different stack frame, or may not get observed at all. I posted some more details about this here.
Why do you ask a question you can answer in a minute by simply testing it?
class Program
{
static void Main(string[] args)
{
MainAsync().Wait();
Console.ReadLine();
}
static async Task MainAsync()
{
await Method1();
}
static async Task Method1()
{
await Method2();
}
static async Task Method2()
{
await Method3();
}
static async Task Method3()
{
Console.Write("Start");
await Task.Delay(1000);
Console.Write("End");
}
}
This creates four different state machines in IL.
The IL code has to be this way, since you can call the methods from anywhere and they have to behave consistently, so any optimization would have to be done on the JIT level, not the C# compiler. If you don't need await, don't use it - that's your responsibility.
A great example would be method overloads:
static Task Method()
{
return Method("Default");
}
static async Task Method(string someString)
{
await SomeThingAsync(someString);
}
It's still just as asynchronous as if you did another await in the parameter-less method - but it avoids a useless state machine.
The only purpose of the async keyword is to allow you to use the await keyword inside a given method. You can still await a method that isn't async - the requirement is returning Task, not having the async keyword.
Using the same example as before, the awaits are superfluous. A simpler way would be this:
class Program
{
static void Main(string[] args)
{
MainAsync().Wait();
Console.ReadLine();
}
static async Task MainAsync()
{
await Method1();
await Method2();
}
static Task Method1()
{
return Method2();
}
static Task Method2()
{
return Method3();
}
static async Task Method3()
{
Console.Write("Start");
await Task.Delay(1000);
Console.Write("End");
}
}
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);
}