Nested Task<T> calls without async/await - c#

This is kind of related to the following post: Why use Async/await all the way down
I am curious what happens in the following scenario:
Updated due to comment:
async Task FooAsync()
{
await Func1();
// do other stuff
}
Task Func1()
{
return Func2();
}
async Task Func2()
{
await tcpClient.SendAsync();
// do other stuff
}
Does this whole process becomes a blocking call? Or because Func1() is actually awaited on, the UI can go and work on something else? Ultimately is it necessary to add the async/await on Func1()? I've played around with it but I don't actually notice any difference, hence the question. Any insight would be great, thanks!

Async and await are just compiler features.
Without await calling async method will cause it to execute synchronous (blocking) way..
When you are writing await all code bellow await is wrapped in Task.ContinueWith() Method by compiler automaticly, this means that when task is finished code below is executed later
public async Task<int> method2(){
return Task.FromResult(1);
}
public void method1(){
await method2()
Console.WriteLine("Done");
}
will translate something like :
public Task<int> method2(){
return Task.FromResult(1);
}
public void method1(){
method2().ContinueWith(x => {
Console.WriteLine("Done");
});
}

The only problem of not making Func1 and async method and not awaiting Func2 in it is that any thrown exception won't show Func1.
The bottom line is that await works on awaitables and Task/Task<T> are awaitables.

Related

Does calling .Result on a task that has already been awaited break the async pattern?

By the time the code calls Task.Result, it has already been awaited, so does the asynchronous pattern here still hold?
class Program
{
static async Task Main(string[] args)
{
var addNumbersTask = AddNumbers(10, 20);
var result = AwaitForResult(addNumbersTask).Result;
Console.WriteLine(result);
}
static async Task<int> AddNumbers(int a, int b)
{
await Task.Delay(250);
return a + b;
}
static async Task<int> AwaitForResult(Task<int> task)
{
await task;
return task.Result;
}
}
Background if you're interested: Trying to emit IL code for a proxy class that needs to handle async calls, but I don't want to generate the async state machine in the IL. So I figured I could delegate the actual "await" part to a helper outside of the IL. Also, I know there are proxy types out there but the hopeless engineer in me wants to write it myself.
Edit: Updated example.
interface IService
{
Task<int> AddAsync(int a, int b);
}
class Service : IService
{
public async Task<int> AddAsync(int a, int b)
{
await Task.Delay(250); // Some web service call...
return a + b;
}
}
// This class 100% generated via reflection emit
class Proxy : IService
{
private readonly IService _actual;
public Proxy(IService actual) => _actual = actual;
public Task<int> AddAsync(int a, int b)
{
return Awaiter.Await(_actual.AddAsync(a, b));
}
}
static class Awaiter
{
public static async Task<int> Await(Task<int> task)
{
return await task;
}
}
class Program
{
static async Task Main(string[] args)
{
var proxy = new Proxy(new Service());
var result = await proxy.AddAsync(5, 5);
Console.WriteLine($"Result is {result}", result);
}
}
does the asynchronous pattern here still hold?
No. There's nothing magical about using await on a task. Instead, consider whether the task is completed. Calling task.Result will block the calling thread until task completes. Doing await task will asynchronously wait until task completes.
So in this code, Result will not block:
static async Task<int> AwaitForResult(Task<int> task)
{
// Task may not yet be complete here.
await task;
// At this point, task is complete.
// Since task is complete, Result does not block.
return task.Result;
}
But that is totally different than this code:
var result = AwaitForResult(addNumbersTask).Result;
// Equivalent to:
var task = AwaitForResult(addNumbersTask);
var result = task.Result;
The task returned from AwaitForResult may not be complete here, since it was never awaited. And if it's not complete, then Result will block.
Trying to emit IL code for a proxy class that needs to handle async calls, but I don't want to generate the async state machine in the IL. So I figured I could delegate the actual "await" part to a helper outside of the IL.
Have you tried Roslyn APIs? I find them much more convenient than IL emit.
If your proxy is just a pass-through, then you can just return the inner task directly:
// This class 100% generated via reflection emit
class Proxy : IService
{
private readonly IService _actual;
public Proxy(IService actual) => _actual = actual;
public Task<int> AddAsync(int a, int b) => _actual.AddAsync(a, b);
}
But if you want to add much real logic, then I'd recommend using Roslyn to generate the async state machine for you.
If you’re trying to avoid blocking, then no.
In your console app example it makes little difference, but if you did that somewhere where you don’t want blocking - e.g. a UI event handler - .Result will still block.
By the time you have a value in addNumbersTask, that task is started. You then immediately pass the task to AwaitForResult, which immediately begins to await it, at which point an incomplete task that returns an int is returned back to main(), and you then call .Result on it. You are now blocking that thread for most of the 250ms until that task returns its int result to .Result in main().
The way you have expressed it in the question, “awaited” does not equal “completed”.
The method Awaiter.Await is basically pointless. Outside of adding some overhead, the returned task will be functionally identical to the one passed in.
The only actual difference in code between simply returning the result of _actual.AddAsync(a, b) and awaiting it is that, if AddAsync throws an exception, if the method is async it will return a faulted task instead of throwing. So if that either can't happen, or if Proxy.AddAsync can safely throw itself in that situation, then simply return the value, no need to do anything. If you need to ensure that Proxy.AddAsync never throws an exception, and instead returns a faulted task if Proxy.AddAsync throws an excpetion, then you simply need to wrap the method in a try/catch and return a faulted exception in the catch block. You don't need to replicate any of the rest of the logic of the async state machine.
So assuming you want the same exception semantics as the behavior of the service's method, which I suspect you do, you can treat these methods exactly the same as you would a synchronous method, that is to say invoke the method with the appropriate parameters and return the result.

Non-Async Method In Async Call Stack [duplicate]

This question already has answers here:
Why use async and return await, when you can return Task<T> directly?
(9 answers)
Closed 5 years ago.
Sorry for a terrible title, I just wanted to confirm that I am making the correct assumptions.
Say I have 3 methods that are simplified to:
public async Task Method1()
{
var obj = await Method2();
//do work on obj
}
public Task<object> Method2()
{
//do some work
return Method3();
}
public async Task<object> Method3()
{
//do async work
return obj;
}
Method2 above does no async work internally, but is in my async stack. It could be rewritten as:
public async Task<object> Method2()
{
//do some work
return await Method3();
}
Am I correct that, as Method2 doesn't actually do async work, that it is better to leave it as a non-async method? My thought is that I'm saving the overhead of creating an extra state machine to hold the thread's resources when it is not needed.
Correct. You can return the Task directly from a method without adding the async/await keywords if the method does not need to await any result (ie. consume the result of a task or wait for a task to complete to be able to do some execution). That returned Task can then be awaited by a caller further down the call stack. This can save a little overhead and make for slightly less code (although that amount of code is actually trivial).
You often see this with pass through or convenience methods.

How to call an async method from another method

I am having a difficult time calling an async method from my current method.
Trying to do something like this:
int i;
public void Method1() {
while (statement1) {
~code~
Method2(i);
}
while (statement2) {
~code~
Method2(i);
}
}
public async void Method2(int i) {
if(statement){
~code~
await Task.Delay(2000);
}
else
{
~code~
await Task.Delay(2000);
}
}
So i want basically Method2 to be a method for controlling the flow (uses another method which changes pictures in pictureboxes), but I can't get it to work and when it works it never delays anything. Does anyone knows what I am doing wrong?
Method2 changes Method1's while statements eventually.
The best practice for async/await is to use async "all the way down" (unless you really and truly don't care about Method1 waiting for Method2 to complete).
It's possible to mix Task.Wait (or similar constructs) with async code, but it's a bad idea because it can lead to deadlocks.
The best thing here would be, as others have indicated, just make Method1 async too:
public async Task Method1() {
while (statement1) {
await Method2(i);
// ...
}
Note that you'll have to make Method1 return a Task too because otherwise you can't wait it:
public async Task Method2
This may be a case of the XY Problem though because there's no reason for the code sample you provide to be async in the first place (or even a separate method, for that matter) - you can just do Thread.Sleep instead. Also, the "if" statement is pointless because, based on what you've shown us, you delay for 2 seconds either way. It would be helpful if you could show a more substantial code sample so we can get a better sense of what you're trying to do so we can recommend whether async is even an appropriate solution here.
One final point: one of the purposes of async/await is to allow the calling thread to do other work while it's waiting for a result - for example, if you want to download a file without "hanging" the UI. I've seen plenty of cases where people use async/await in a way that essentially obviates the purpose though. For example:
static void Main(string[] args) {
// This is a terrible thing to do but it's for illustration purposes
Task task = Method1();
task.Wait();
// Some other work
}
private static async Task Method1() {
await Method2();
// Some other work
}
private static async Task Method2() {
await Method3();
// Some other work
}
private static async Task Method3() {
await Task.Delay(1000);
}
This is a pretty dumb illustration, granted, but in this case the async/await is completely pointless because it's just doing each action sequentially anyway.
For another method to be able to await Method2 the latter must return have a return type of Task or Task (and not void):
public async Task Method2(int i) {
if(statement){
~code~
await Task.Delay(2000);
}
else
{
~code~
await Task.Delay(2000);
}
Method1 should then be marked as async and await Method2:
public async void Method1() {
while (statement1) {
~code~
await Method2(i);
}
while (statement2) {
~code~
await Method2(i);
}
}
You should make Method1 also asyncronous and add await operator for Method2 call:
public async Task Method1() {
while (statement1) {
~code~
await Method2(i);
}
while (statement2) {
~code~
await Method2(i);
}
}
public async Task Method2(int i) {
if(statement){
~code~
await Task.Delay(2000);
}
else
{
~code~
await Task.Delay(2000);
}
}
If you need Method1 to be syncronous for some reason, you should call Wait() on task returned from Method2. However it's considered as bad practice because you loose advantage of .NET thread pool.

How to create a Task which always yields?

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.

Implementing async version of a sync method: How to return Task<int> which is constant 1?

I have a sync method, now I would like to implement its async version. Fortunately the underlying call already have an async version (dbSet.SaveChangesAsync()), however in my algorithm there is an if branch returning with constant literal 1.
I do not know how to implement this part in the async version?
Sync version:
public virtual int Add(T entity)
{
SetLogContext(entity, _logctx);
dbSet.Add(entity);
if (isAutonomous)
{
return ctx.SaveChanges();
}
return 1;
}
Async version:
public virtual Task<int> AddAsync(T entity)
{
SetLogContext(entity, _logctx);
dbSet.Add(entity);
if (isAutonomous)
{
return ctx.SaveChangesAsync();
}
return ??? // What to write here?
}
Use
return Task.FromResult(1);
You have two possibilities how to achieve your needs: one is to use the async keyword:
public virtual async Task<int> AddAsync<T>(T entity)
{
SetLogContext(entity, _logctx);
dbSet.Add(entity);
if (isAutonomous)
{
return await ctx.SaveChangesAsync();
}
return 1;
}
The other is to use Task.FromResult(1) at the point where you want to return the number.
The problem I see here is that you've created an "Async" method that isn't actually async. This could be pretty misleading for the next guy using it.
As #xxMUROxx already mentioned, an "Async" method should be prefixed with the async keyword.
public virtual async Task<int> AddAsync<T>(T entity)
{
SetLogContext(entity, _logctx);
dbSet.Add(entity);
if (isAutonomous)
{
return await ctx.SaveChangesAsync();
}
return 1;
}
The whole point of using the async await pattern is to change the way the program flows through methods. When the await keyword is hit, the method returns to the caller and usually flows all the way back to the original caller. Typically that'll be an async void event handler like a button click.
When this happens, it allows the calling thread to continue executing while it's waiting for a long running operation to complete. After the long running operation completes the code will create a continuation and continue executing any other code that depends on the result returned.
By omitting the async keyword from the method, you've effectively made the call synchronous again. Defeating the purpose of calling SaveChangesAsync in the first place.

Categories