awaiting inside an awaitable function in .net - c#

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?).

Related

How can an "async" task return an integer and not a public one?

I just had following piece of code, which did not compile:
public Task<int> Handle
{
var result = <do_something_returning_an_int>();
...
return result;
}
This gives compiler error `cannot implicitly convert type 'int' to 'System.Threading.Thread.Task'.
When I change this into:
async Task<int> Handle
{
var result = <do_something_returning_an_int>();
...
return result;
}
... no compiler error.
I know that async means that the task does not need to wait for the answer to arrive, but what does this have to do with typecasting?
If you're not awaiting anything in your asynchronous method you omit the async keyword and return a Task instead of the result directly.
public Task<int> Handle
{
var result = <do_something_returning_an_int>();
...
return Task.FromResult(result);
}
As far as I can tell, doing that only makes sense if other code strictly expects a Task from your method.
This has of course nothing to do with access modifiers, you can combine async with public or any other access modifier.
I'd also recommend taking a look at the documentation
(By request, promoted from a comment.)
This is by design of the async logic in the C# Language Specification. See the section Async Functions.
You can also read the programming guide, Async return types (C#) ยง Task<TResult>.
The point is that a method without the async keyword, like
public Task<int> HandleAsync()
{
...
Task<int> result = ...;
...
return result;
}
must return what it says it returns, just as with all other types. In this case, you could create a Task<> that can be awaited, in your own manual way, like:
Task<int> result = Task.Run(GetLastDigitOfSmallestTwinPrimeWithMoreThan1000000Digits);
The caller can await the task you return, even if your method is written like above.
But if you use the async keyword, and if your return type is, say, Task<int>, then you must return a plain int, and the C# compiler will write the needed logic for you.
Usually, you would use await somewhere in the body (otherwise, why async). So something like:
public async Task<int> HandleAsync()
{
...
int result = await GetLastDigitOfSmallestTwinPrimeWithMoreThan1000000DigitsAsync();
...
return result;
}
Related question here: Why is it not necessary to return a Task when the signature is public async Task MethodName?
try using task result and then iterate the results
Task<int> Handle
{
return Task.Run(()=>
{
var result = <do_something_returning_an_int>();
...
return result;
}
}
List<Task<int>> tasks = new List<Task<int>>();
tasks.Add(Handle);
Task.WaitAll(tasks.ToArray());
for(int ctr = 0; ctr < tasks.Count; ctr++) {
if (tasks[ctr].Status == TaskStatus.Faulted)
output.WriteLine(" Task fault occurred");
else
{
output.WriteLine("test sent {0}",
tasks[ctr].Result);
Assert.True(true);
}
}
or
Task<int> Handle
{
return Task.FromResult(do_something_returning_an_int);
}

await Task.CompletedTask vs return

I'm trying to understand the difference between await Task.CompletedTask and return but can't seem to find any clearly defined explanation.
Why / when would you use this:
public async Task Test()
{
await Task.CompletedTask;
}
over this?
public async Task Test()
{
return;
}
It's my understanding that both will have their status set to TaskStatus.RanToCompletion though I have the feeling it might have to do with physical time or something like that based on the explanation from Task.FromResult:
The method is commonly used when the return value of a task is immediately known without executing a longer code path.
Would appreciate a clear demystification of this as I've studied MS code on GitHub, the MS Docs as well as every link I could find but nowhere does it give a clear explanation. I also see await Task.CompletedTask at the end of larger methods which per some comments I found from MS on GitHub is actually in error as it's not supposed to contain that and they want to get it cleaned out of the repo.
If also a clear demystification of Task.FromResult (since they're siblings) that would be appreciated as I'm also still unclear of when to use:
public async Task<bool> Test()
{
return await Task.FromResult(true);
}
over this:
public async Task<bool> Test()
{
return true;
}
Let's look the question from the consumer-side.
If you define an interface, which imposes an operation that returns a Task then you don't say anything about how it will be calculated / executed (so, there is no async access modifier in the method signature). It is an implementation detail.
Interface
public interface ITest
{
Task Test();
Task<bool> IsTest();
}
So, it is up to you how you implement the interface.
You can do it in a synchronous way, when there won't be any AsyncStateMachine generated because of the absence of the async keyword.
Implementation #1
public class TestImpl : ITest
{
public Task Test()
{
return Task.CompletedTask;
}
public Task<bool> IsTest()
{
return Task.FromResult(true);
}
}
Or you can try to implement it in an asynchronous way but without await operators. Here you will receive CS1998 warnings.
Implementation #2
public class TestImpl : ITest
{
public async Task Test()
{
return;
}
public async Task<bool> IsTest()
{
return true;
}
}
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.
In other words this implementation does not define a state machine. An async method is divided into different states based on the await keywords:
before_the_await_1,
after_the_await_1_but_before_the_await_2
after_the_await_2_but_before_the_await_3
...
If you haven't got any await then you would have a single state, which would run in sync (there is no need to preserve state, execute async operation and then call MoveNext()).
Or you can try to implement it in an asynchronous way with await operators.
Implementation #3
public class TestImpl : ITest
{
public async Task Test()
{
await Task.CompletedTask;
}
public async Task<bool> IsTest()
{
return await Task.FromResult(true);
}
}
In this case there will be an async state machine but it won't be allocated on the heap. By default it is a struct and if it finishes in sync then we don't need to allocate them on the heap to extend its life out of the scope of the method.
For further information please read these articles:
Async/await in .NET Core 3.x
Async ValueTask Pooling in .NET 5
Dissecting the async methods in C#
return; means you exit the function
await Task.CompletedTask; just continues execution of the rest of the function body.

Cannot implicitly convert type 'void' to 'object' on GetAwaiter().GetResult()

We have used the following code to await method execution since we have sync methods that must consume async methods and this is a wrapper we have used in our project
public dynamic RunTask(dynamic method) {
var result = Task.Run(async () => await method).ConfigureAwait(false);
return result.GetAwaiter().GetResult();
}
Seems like this line of code works fine when the method have return types ex: Task< int > but today when I have written non-return method it throws an exception when there is no return value from Task
// throws exception in this case 'Cannot implicitly convert type 'void' to 'object'
public async Task Run(){
await //;
}
// Works
public async Task<int> Fun(){
return await //;
}
From the message, it is clearly unable to assign void to object but is there something I am missing how do I make it work void tasks. We are using .net core 3.1. Any help is greatly appreciated.
Are you calling RunTask(); with the method not returning anything? :)
You can try this code for your purpose, however as Marc suggested, this is not recommended practice:
public dynamic RunTask(dynamic method)
{
if (method is Task)
{
method.ConfigureAwait(false).GetAwaiter().GetResult();
return 0;
}
else
{
var result = Task.Run(async () => await method).ConfigureAwait(false);
return result.GetAwaiter().GetResult();
}
}
First of this a bad practice. The best way to async call is following await pattern. This goes something like this
private Task MyMethodAsync(){
}
public async void Main(){
await MyMethodAsync();
}
Now it can be a bit difficult to implement await pattern if it's not already in place (as it may require await-ing all the calls in chain). What you can you do is the following:
MyMethodAsync().Wait()
This will block the calling thread and wait till the task is done. Since it's void you won't get any result and that's the main reason you are getting this exception in the first place.

Where is the return statement in async/await

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.

Using async without await

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

Categories

Resources