A quick google search will tell you to avoid using async void myMethod() methods when possible. And in many cases there are ways to make it possible. My question is basically an offshoot of this best practice:
What does the lambda expression below evaluate to?
Task.Run( async ()=> await Task.Delay(1000));
If it becomes an async Task then we are following best practice.
But what if it evaluates to async void?
The documentation for expression lambdas says,
An expression lambda returns the result of the expression
So, for example, () => "hi" returns a string, even though there is no return statement. But if the expression doesn't return anything, like in () => Console.WriteLine("hi"), then it's considered void.
However there is a bit of trickery with async lambdas. The expression await Task.Delay(1000) doesn't really return anything in itself. However, the language can figure out that if you have an async lambda, you likely want it to return a Task. So it will prefer that.
So this:
Task.Run(async () => await Task.Delay(1000));
Is equivalent to this, if you were to express it with a named method:
private async Task Wait1000() {
await Task.Delay(1000);
}
Task.Run(Wait1000);
But it is important to note that async lambdas can be inferred to be async void. The only reason it is considered async Task here is because Task.Run has an overload for Func<Task>. If the only available overload took an Action parameter, then it would be inferred to be async void, without any warning to you.
For example, this produces no error and the lambda is treated as async void:
private void RunThisAction(Action action) {
action();
}
RunThisAction(async () => await Task.Delay(1000));
That is different than if you passed it a named async Task method, which would cause a compiler error:
private void RunThisAction(Action action) {
action();
}
private async Task Wait1000() {
await Task.Delay(1000);
}
RunThisAction(Wait1000); // 'Task Wait1000()' has the wrong return type
So be careful where you use it. You can always hover over the method name (like the Run in Task.Run) and Visual Studio will tell you which overload it has inferred:
Yeah, it is evaluated to async Task because Task.Delay(n) has return type of Task. So it is good practice.
In addition, there is msdn example, but it is a little bit more verbose:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
button1.Click += async (sender, e) =>
{
await ExampleMethodAsync();
textBox1.Text += "\r\nControl returned to Click event handler.\n";
};
}
private async Task ExampleMethodAsync()
{
// The following line simulates a task-returning asynchronous process.
await Task.Delay(1000);
}
}
So the above code could be shortened to:
public Form1()
{
InitializeComponent();
button1.Click += async (sender, e) =>
{
await Task.Delay(1000);
textBox1.Text += "\r\nControl returned to Click event handler.\n";
};
}
}
And now shortened code looks like your code.
Related
I have a function that returns a Task
class Sample
{
TaskCompletionSource<int> _tcs;
..
public Task<int> DoIt(){
StartDoingStuff();
return _tcs.Task;
}
..
private void FinshedStuffCallBack(){
_tsc.SetResult(42);
}
}
Caller goes
var sample = new Sample();
var result = await Sample.DoIt();
works fine
Now I need to do something in addition in DoIt, this is itself awaitable
I naively tried
public async Task<int> DoIt(){
await DoOtherAsyncStuff();
StartDoingStuff();
return _tcs.Task;
}
but this is not allowed
CS4016 Since this is an async method, the return expression must be of
type 'int' rather than 'Task'
OK I get what its trying to say, but thats not my intention, I dont have the return value yet, it comes once StartDoingStuff triggers the callback.
Not sure what to try next.
Most likely you just need (note the await on the last line):
public async Task<int> DoIt()
{
await DoOtherAsyncStuff();
StartDoingStuff();
return await _tcs.Task;
}
await is needed on the last line because an async function returning Task<int> needs to return int, while _tcs.Task is a Task<int>. Using await will wait for the Task's completion and return the int which is what we need.
However, depending on your complete code you may want something else. For example if you're doing more complicated things with TaskCompletionSource you may need to remove async for this definition and do something like
public Task<int> DoIt()
{
return DoOtherAsyncStuff().ContinueWith(_ =>
{
StartDoingStuff();
return _tcs.Task;
}, TaskCompletionOptions.ExecuteSynchronously);
}
In general it's best not to mess with TaskCompletionSource unless you're doing something more advanced, for example providing an async abstraction of something synchronous/callback based. Hence a complete code example may change my answer (for example what's the body of StartDoingStuff + DoOtherAsyncStuff?).
I'm a beginner with the async/await and I'm getting an error on my code that I'm not able to figure out how to fix it:
public static Func<string> GetTheID;
void Main()
{
GetTheID = async () => await GetMyId(); //Error here!
Console.WriteLine(GetTheID);
}
public async Task<string> GetMyId()
{
return await Task.Run(() =>
{
return "AAABBBB";
});
}
I'm getting this error:
Cannot convert async lambda expression to delegate type
'Func<string>'. An async lambda expression may return void, Task or
Task<T>, none of which are convertible to 'Func<string>'
Could you please help me how to fix this error without changing the signature of the GetTheID delegate (I means without changing its signature to Func<Task<string>>)?
You have to change the signature of the GetTheID, and there isn't any other way. So as the error suggest, you need to change the type of GetTheID to Func<Task<string>>, it has to return a Task or Task<T> in order to be able to await it:
public static Func<Task<string>> GetTheID;
Starting with C# 7.1, you can actually have an async Main() function, which enables you to use await in the described situation:
static async Task<int> Main(string[] args)
{
return await AsyncConsoleWork();
}
It seems that you are trying to adapt an asynchronous method to work in a synchronous way.
If this is the correct context your approach could be
void Main()
{
GetTheID = () => GetMyId().Result;
Console.WriteLine(GetTheID.Invoke());
}
use this:
void Main()
{
GetTheID = () => GetMyId().GetAwaiter().GetResult();
Console.WriteLine(GetTheID);
}
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();
}
I have probably worked myself into a rather immature confusion. Please refer the code below (console app)
namespace Tasks101
{
class Program
{
static void Main(string[] args)
{
Program p = new Program();
var x = p.Blah();
}
private async Task Blah()
{
await Task.Delay(TimeSpan.FromSeconds(3)).ConfigureAwait(false);
}
private async void ReturnsVoid()
{
await Task.Delay(TimeSpan.FromSeconds(3)).ConfigureAwait(false);
}
private void Nothing()
{
}
}
}
My question is that in Blah() method I don't have any explicit return statement yet when this executes
var x = p.Blah();
the type of x is Task. Again I have no return statement in ReturnsVoid method but that compiles too.
So the questions are
What is returning a Task from the Blah method without my having a return statement there and why is that same thing not returning anything from ReturnsVoid method.
How do I control what gets returned from the Blah method? What if I had two await statements there one after the other?
The async keyword transforms the method and constructs the returned Task instance. There is nothing returned from the async void method because it returns void; this lack of a Task is one reason why you should avoid async void. async void is not a natural asynchronous method signature; it is only supported so that event handlers may be async.
If you want to return a value, then you should have the method return a Task<T>, e.g., Task<int> BlahAsync(), and then you can just return the value directly, e.g., return 13; The number of awaits in the method has nothing to do with it. When the method executes the actual return (e.g., return 13), the async keyword interprets that as completing the Task<int> that was already constructed.
I have an async intro on my blog that you may find helpful.
The compiler is generating a Task for you that represents the entire asynchronous operation.
You have 3 options for async methods:
async void - This should be avoided in all cases other than event handlers
async Task - Here you have no control of the returned task, and it will be completed when the whole operation has ended (or when an exception is thrown) no matter how many awaits you have in it.
async Task<T> - This allows to actually return a value but behaves just the same as async Task.
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