Cancel only the inner Task when awaiting an async function? - c#

I am trying to extend a framework, where our users of the framework can use C# as a language with non-blocking functions (aka "coroutines"). My first design used yield return statements and an IEnumerator as function return value.
However, that is quite a bit error prone and awkward to use if you try to call another yielding function (and even more if the other function should return a value).
So I am toying with the idea of using async and await to provide the corountines. The resulting syntax would be so much more fun.
In our framework, I need to ensure that no two of these non-blocking scripts ever run in parallel, so I wrote my own SynchonizationContext to schedule all actions by myself. That works like a charm.
Now the more interesting stuff: Another core part of our design is, that users can register some kind of "check functions" that will not continue the "current" executing function if they are failing. The check functions should be executed every time the non-blocking function resumes.
So for example:
async Task DoSomething()
{
var someObject = SomeService.Get(...);
using (var check = new SanityCheckScope())
{
check.StopWhen(() => someObject.Lifetime < 0);
...
await SomeOtherStuff();
// when execution comes back in here, the StopWhen - condition above should be
// evaluated and the Task should not be scheduled if its true.
...
}
}
Whenever SomeOtherStuff or any asynchronous function called by it resumes, the registered condition should be checked and DoSomething should stop if any condition is true.
To implement this, my SynchonizationContext checks the registered functions (passed via CallContext.LogicalSetData) and just does not schedule the task if one returns true.
Now comes the tricky problem. Suppose the function SomeOtherStuff looks like this:
async Task SomeOtherStuff()
{
using (var check = new SanityCheckScope())
{
// register my own check functions
await Whatever();
}
}
In the example SomeOtherStuff registers its own check function. If they are true after the await Whatever(), naturally only the SomeOtherStuff function should be stopped. (Lets assume that if SomeOtherStuff returns a Task<XXX>, then it would be OK for me if default(XXX) would be used as return value.)
How could I approach this? I can't get to the Action that comes after the await SomeOtherStuff(); in my original function. There seem to be no hook or callback at the begin of an await either (nor would it make sense anyway).
Another idea would be to throw an exception instead of "not scheduling" the task. Instead (or additional to) the using-block, I would write a try/catch. However, then I got the problem that if any check function of the original DoSomething fails after the inner await Whatever(); how would I stop DoSomething (together with SomeOtherStuff)?
So before I scratch all this and go back to my IEnumerator and yield return.. Anyone got an idea whether this can be done by the async / await framework?

My recommendation is to just use TPL Dataflow and be done with it. The more you abuse a language feature like async (or IEnumerable for that matter), the less maintainable your code is.
That said...
You do (sort of) have some hooks around await: custom awaitables. Stephen Toub has a blog on them and Jon Skeet covers some details in his eduasync series.
However, you cannot return a custom awaitable from an async method, so this approach would mean all your awaits would have to "opt-in" to the "check" behavior:
async Task DoSomething()
{
var someObject = SomeService.Get(...);
using (var check = new SanityCheckScope())
{
check.StopWhen(() => someObject.Lifetime < 0);
await SomeOtherStuff().WithChecks();
}
}
It's not clear to me what the semantics should be when a check fails. From your question, it sounds like once a check fails you just want that method to abort, so the check is more like a code contract than a monitor or condition variable. It also sounds like the scope should only be applied to that method and not methods called from that method.
You may be able to get something working by using a custom awaiter which encapsulates the returned Task and uses TaskCompletionSource<T> to expose a different Task. The custom awaiter would perform the check before executing the continuation of the async method.
Another thing to watch out for is how your "scope" works. Consider this situation:
async Task DoSomething()
{
using (var check = new SanityCheckScope())
{
check.StopWhen(...);
await SomeOtherStuff();
await MoreOtherStuff();
}
}
Or even more fun:
async Task DoSomething()
{
using (var check = new SanityCheckScope())
{
check.StopWhen(...);
await SomeOtherStuff();
await Task.WhenAll(MoreOtherStuff(), MoreOtherStuff());
}
}
I suspect your scope will have to make use of AsyncLocal<T> (described on my blog) in order to work properly.

Have you considered implementing your own SynchronizationContext? You could either implement your own (assuming there is no meaningful SynchronizationContext already installed) or you could perhaps install a wrapper around an existing context.
The await syntax will post the continuation to the SynchronizationContext (assuming the await is not configured not to do so) which would allow you to intercept it. Of course any asynchronous callback will be posted to the SynchronizationContext so it may not be straightforward to detect the exact moment the continuation is called, so this could cause the sanity check to happen for all callbacks posted to the context.
Your SanityCheckScope can ensure that a checking scope is registered in a nested fashion with your SynchronizationContext where, obviously, the IDisposable part of your class deregisters and reinstates the parent scope. This would only work if you don't have a situation where you can have multiple parallel child scopes.
The only way to stop execution is, as far as I can see, to throw some kind of exception.

Related

What is the proper way to await for async inside of a ForEach?

.NET Core 2.2, VS 2019
The problem is, the UpdateDatabaseWithFile is never getting executed? What am I doing wrong here? I tried to wrap Directory with an await, but I can't, since it returns void. What is the proper way to do this?
Here is the code:
Directory
.GetFiles(#"C:\Temp")
.ToList()
.ForEach(async file =>
{
await this._dataService.UpdateDatabaseWithFile();
});
It is because ForEach<T> just executes that async functions, but didn't wait for their completion.
You can use Select for projecting Tasks which has to be executed and then use Task.WhenAll() to execute that functions and wait for their completion:
var tasks = Directory
.GetFiles(#"C:\Temp")
.Select(async file =>
{
await this._dataService.UpdateDatabaseWithFile();
});
await Task.WhenAll(tasks);
Or if you want to execute functions sequentally, then instead of Task.WhenAll() you can use simple foreach:
foreach (var file in Directory.GetFiles(#"C:\Temp"))
{
await this._dataService.UpdateDatabaseWithFile();
}
Additional explanation:
Here is the implementation of ForEach<T>:
for(int i = 0 ; i < array.Length; i++) {
action(array[i]);
}
As you see it just executes that action but didn't wait for their completion. And actually, it can't. Action returns nothing. But for waiting Task has to be returned. So, for making ForEach function useful in that situation, it has to take Func which return Task and then await inside for iterator..
The method List.ForEach doesn't understand async delegates, in other words it hasn't an overload that accepts a Func<Task<T>> parameter. In these cases what happens is that the supplied async lambda is treated as async void. Async voids are evil, because they can't be awaited, so their execution can't be coordinated with other parts of the program. They are similar to fire-and-forget tasks, with the added drawback of killing the process in case of an exception.
Void-returning async methods have a specific purpose: to make asynchronous event handlers possible.
You should pay attention to the signature of the method you are attempting to call with an async delegate as argument. Some methods like Task.Run have specific overloads for async delegates, and handle them well. Other methods like the LINQ Select are not designed with async await in mind, but at least they accept arguments of type Func instead of Action, and so the generated tasks are returned and can be collected and awaited properly. Methods like the List.ForEach with Action arguments should never be used with async delegates.
The most likely problem here is that .ForEach() provides no way for you to actually wait for the operations to complete. It will just execute them and move on.
Eric Lippert has a good blog post on why the .ForEach() method isn't all that great, and this is a perfect example of how a foreach loop excels over .ForEach - foreach will allow you to actually await the operations.
Just use a loop, and your problems go away:
foreach (var file = Directory.GetFiles(#"C:\Temp"))
{
await this._dataService.UpdateDatabaseWithFile();
}
It should be noted that you don't seem to actually be using the file variable anywhere, and that seems like a problem. Hopefully just a typo?

How does using await differ from using ContinueWith when processing async tasks?

Here's what I mean:
public Task<SomeObject> GetSomeObjectByTokenAsync(int id)
{
string token = repository.GetTokenById(id);
if (string.IsNullOrEmpty(token))
{
return Task.FromResult(new SomeObject()
{
IsAuthorized = false
});
}
else
{
return repository.GetSomeObjectByTokenAsync(token).ContinueWith(t =>
{
t.Result.IsAuthorized = true;
return t.Result;
});
}
}
Above method can be awaited and I think it closely resembles to what the Task-based Asynchronous Pattern suggests doing? (The other patterns I know of are the APM and EAP patterns.)
Now, what about the following code:
public async Task<SomeObject> GetSomeObjectByToken(int id)
{
string token = repository.GetTokenById(id);
if (string.IsNullOrEmpty(token))
{
return new SomeObject()
{
IsAuthorized = false
};
}
else
{
SomeObject result = await repository.GetSomeObjectByTokenAsync(token);
result.IsAuthorized = true;
return result;
}
}
The key differences here are that the method is async and it utilizes the await keywords - so what does this change in contrast to the previously written method? I know it can too - be awaited. Any method returning Task can for that matter, unless I'm mistaken.
I'm aware of the state machine created with those switch statements whenever a method is labeled as async, and I'm aware that await itself uses no thread - it doesn't block at all, the thread simply goes to do other things, until it's called back to continue execution of the above code.
But what's the underlying difference between the two methods, when we invoke them using the await keyword? Is there any difference at all, and if there is - which is preferred?
EDIT: I feel like the first code snippet is preferred, because we effectively elide the async/await keywords, without any repercussions - we return a task that will continue its execution synchronously, or an already completed task on the hot path (which can be cached).
The async/await mechanism makes the compiler transform your code into a state machine. Your code will run synchronously until the first await that hits an awaitable that has not completed, if any.
In the Microsoft C# compiler, this state machine is a value type, which means it will have a very small cost when all awaits get completed awaitables, as it won't allocate an object, and therefore, it won't generate garbage. When any awaitable is not completed, this value type is inevitably boxed. 1
Note that this doesn't avoid allocation of Tasks if that's the type of awaitables used in the await expressions.
With ContinueWith, you only avoid allocations (other than Task) if your continuation doesn't have a closure and if you either don't use a state object or you reuse a state object as much as possible (e.g. from a pool).
Also, the continuation is called when the task is completed, creating a stack frame, it doesn't get inlined. The framework tries to avoid stack overflows, but there may be a case where it won't avoid one, such as when big arrays are stack allocated.
The way it tries to avoid this is by checking how much stack is left and, if by some internal measure the stack is considered full, it schedules the continuation to run in the task scheduler. It tries to avoid fatal stack overflow exceptions at the cost of performance.
Here is a subtle difference between async/await and ContinueWith:
async/await will schedule continuations in SynchronizationContext.Current if any, otherwise in TaskScheduler.Current 2
ContinueWith will schedule continuations in the provided task scheduler, or in TaskScheduler.Current in the overloads without the task scheduler parameter
To simulate async/await's default behavior:
.ContinueWith(continuationAction,
SynchronizationContext.Current != null ?
TaskScheduler.FromCurrentSynchronizationContext() :
TaskScheduler.Current)
To simulate async/await's behavior with Task's .ConfigureAwait(false):
.ContinueWith(continuationAction,
TaskScheduler.Default)
Things start to get complicated with loops and exception handling. Besides keeping your code readable, async/await works with any awaitable.
Your case is best handled with a mixed approach: a synchronous method that calls an asynchronous method when needed. An example of your code with this approach:
public Task<SomeObject> GetSomeObjectByTokenAsync(int id)
{
string token = repository.GetTokenById(id);
if (string.IsNullOrEmpty(token))
{
return Task.FromResult(new SomeObject()
{
IsAuthorized = false
});
}
else
{
return InternalGetSomeObjectByTokenAsync(repository, token);
}
}
internal async Task<SomeObject> InternalGetSomeObjectByToken(Repository repository, string token)
{
SomeObject result = await repository.GetSomeObjectByTokenAsync(token);
result.IsAuthorized = true;
return result;
}
In my experience, I've found very few places in application code where adding such complexity actually pays off the time to develop, review and test such approaches, whereas in library code any method can be a bottleneck.
The only case where I tend elide tasks is when a Task or Task<T> returning method simply returns the result of another asynchronous method, without itself having performed any I/O or any post-processing.
YMMV.
When building for Release, the compiler generates structs.
When building for Debug, the compiler generates classes to allow edit-and-continue on async code.
Unless you use ConfigureAwait(false) or await on some awaitable that uses custom scheduling.
By using ContinueWith you are using the tools that where available before the introduction of the async/await functionality with C# 5 back at 2012. As a tool it is verbose, not easily composable, it has a potentially confusing default scheduler¹, and requires extra work for unwrapping AggregateExceptions and Task<Task<TResult>> return values (you get these when you pass asynchronous delegates as arguments). It offers few advantages in return. You may consider using it when you want to attach multiple continuations to the same Task, or in some rare cases where you can't use async/await for some reason (like when you are in a method with out parameters).
¹ If the scheduler argument is not provided, it defaults to TaskScheduler.Current, and not to TaskScheduler.Default as one might expect. This means that by default when the ContinueWith is attached, the ambient TaskScheduler.Current is captured, and used for scheduling the continuation. This is somewhat similar with how the await captures the ambient SynchronizationContext.Current, and schedules the continuation after the await on this context. To prevent this behavior of await you can use the ConfigureAwait(false), and to prevent this behavior of ContinueWith you can use the TaskContinuationOptions.ExecuteSynchronously flag in combination with passing the TaskScheduler.Default. Most experts suggest to specify always the scheduler argument every time you use the ContinueWith, and not rely on the ambient TaskScheduler.Current. Specialized TaskSchedulers are generally doing more funky stuff than specialized SynchronizationContexts. For example the ambient scheduler could be a limited concurrency scheduler, in which case the continuation might be put in a queue of unrelated long-running tasks, and executed a long time after the associated task has completed.

Chaining arbitrary number of tasks together in C#.NET

What I have
I have a set of asynchronous processing methods, similar to:
public class AsyncProcessor<T>
{
//...rest of members, etc.
public Task Process(T input)
{
//Some special processing, most likely inside a Task, so
//maybe spawn a new Task, etc.
Task task = Task.Run(/* maybe private method that does the processing*/);
return task;
}
}
What I want
I would like to chain them all together, to execute in sequential order.
What I tried
I have tried to do the following:
public class CompositeAsyncProcessor<T>
{
private readonly IEnumerable<AsyncProcessor<T>> m_processors;
//Constructor receives the IEnumerable<AsyncProcessor<T>> and
//stores it in the field above.
public Task ProcessInput(T input)
{
Task chainedTask = Task.CompletedTask;
foreach (AsyncProcessor<T> processor in m_processors)
{
chainedTask = chainedTask.ContinueWith(t => processor.Process(input));
}
return chainedTask;
}
}
What went wrong
However, tasks do not run in order because, from what I have understood, inside the call to ContinueWith, the processor.Process(input) call is performed immediately and the method returns independently of the status of the returned task. Therefore, all processing Tasks still begin almost simultaneously.
My question
My question is whether there is something elegant that I can do to chain the tasks in order (i.e. without execution overlap). Could I achieve this using the following statement, (I am struggling a bit with the details), for example?
chainedTask = chainedTask.ContinueWith(async t => await processor.Process(input));
Also, how would I do this without using async/await, only ContinueWith?
Why would I want to do this?
Because my Processor objects have access to, and request things from "thread-unsafe" resources. Also, I cannot just await all the methods because I have no idea about how many they are, so I cannot just write down the necessary lines of code.
What do I mean by thread-unsafe? A specific problem
Because I may be using the term incorrectly, an illustration is a bit better to explain this bit. Among the "resources" used by my Processor objects, all of them have access to an object such as the following:
public interface IRepository
{
void Add(object obj);
bool Remove(object obj);
IEnumerable<object> Items { get; }
}
The implementation currently used is relatively naive. So some Processor objects add things, while others retrieve the Items for inspection. Naturally, one of the exceptions I get all too often is:
InvalidOperationException: Collection was modified, enumeration
operation may not execute.
I could spend some time locking access and pre-running the enumerations. However, this was the second option I would get down to, while my first thought was to just make the processes run sequentially.
Why must I use Tasks?
While I have full control in this case, I could say that for the purposes of the question, I might not be able to change the base implementation, so what would happen if I were stuck with Tasks? Furthermore, the operations actually do represent relatively time-consuming CPU-bound operations plus I am trying to achieve a responsive user interface so I needed to unload some burden to asynchronous operations. While being useful and, in most of my use-cases, not having the necessity to chain multiple of them, rather a single one each time (or a couple, but always specific and of a specific count, so I was able to hook them together without iterations and async/await), one of the use-cases finally necessitated chaining an unknown number of Tasks together.
How I deal with this currently
The way I am dealing with this currently is to append a call to Wait() inside the ContinueWith call, i.e.:
foreach (AsyncProcessor<T> processor in m_processors)
{
chainedTask = chainedTask.ContinueWith(t => processor.Process(input).Wait());
}
I would appreciate any idea on how I should do this, or how I could do it more elegantly (or, "async-properly", so to speak). Also, I would like to know how I can do this without async/await.
Why my question is different from this question, which did not answer my question entirely.
Because the linked question has two tasks, so the solution is to simply write the two lines required, while I have an arbitrary (and unknown) number of tasks, so I need an suitable iteration. Also, my method is not async. I now understand (from the single briefly available answer, which was deleted) that I could do it fairly easily if I changed my method to async and await each processor's Task method, but I still wish to know how this could be achieved without async/await syntax.
Why my question is not a duplicate of the other linked questions
Because none of them explains how to chain correctly using ContinueWith and I am interested in a solution that utilizes ContinueWith and does not make use of the async/await pattern. I know this pattern may be the preferable solution, I want to understand how to (if possible) make arbitrary chaining using ContinueWith calls properly. I now know I don't need ContinueWith. The question is, how do I do it with ContinueWith?
foreach + await will run Processes sequentially.
public async Task ProcessInputAsync(T input)
{
foreach (var processor in m_processors)
{
await processor.Process(input));
}
}
Btw. Process, should be called ProcessAsync
The method Task.ContinueWith does not understand async delegates, like Task.Run do, so when you return a Task it considers this as a normal return value and wraps it in another Task. So you end up receiving a Task<Task> instead of what you expected to get. The problem would be obvious if the AsyncProcessor.Process was returning a generic Task<T>. In this case you would get a compile error because of the illegal casting from Task<Task<T>> to Task<T>. In your case you cast from Task<Task> to Task, which is legal, since Task<TResult> derives from Task.
Solving the problem is easy. You just need to unwrap the Task<Task> to a simple Task, and there is a built-in method Unwrap that does exactly that.
There is another problem that you need to solve though. Currently your code suppresses all exceptions that may occur on each individual AsyncProcessor.Process, which I don't think it was intended. So you must decide which strategy to follow in this case. Are you going to propagate the first exception immediately, or you prefer to cache them all and propagate them at the end bundled in an AggregateException, like the Task.WhenAll does? The example bellow implements the first strategy.
public class CompositeAsyncProcessor<T>
{
//...
public Task Process(T input)
{
Task current = Task.CompletedTask;
foreach (AsyncProcessor<T> processor in m_processors)
{
current = current.ContinueWith(antecessor =>
{
if (antecessor.IsFaulted)
return Task.FromException<T>(antecessor.Exception.InnerException);
return processor.Process(input);
},
CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default
).Unwrap();
}
return current;
}
}
I have used an overload of ContinueWith that allows configuring all the options, because the defaults are not ideal. The default TaskContinuationOptions is None. Configuring it to ExecuteSynchronously you minimize the thread switches, since each continuation will run in the same thread that completed the previous one.
The default task scheduler is TaskScheduler.Current. By specifying TaskScheduler.Default you make it explicit that you want the continuations to run in thread-pool threads (for some exceptional cases that won't be able to run synchronously). The TaskScheduler.Current is context specific, and if it ever surprises you it won't be in a good way.
As you see there are a lot of gotchas with the old-school ContinueWith approach. Using the modern await in a loop is a lot easier to implement, and a lot more difficult to get it wrong.

In .NET, are async methods exclusively those with the async keyword?

I've been learning about HttpClient (consuming API's in .NET in general), and therefore about async programming. I'm still pretty lost right now, so trying to clear some things up. One question I can't seem to find an answer to - are asynchronous methods implemented exclusively using the async keyword?
I understand that you could (theoretically) create synchronous methods using async programming, but how do you recognize that? For example, from this link and this example:
public string GetReleases(string url)
{
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Add(RequestConstants.UserAgent, RequestConstants.UserAgentValue);
var response = httpClient.GetStringAsync(new Uri(url)).Result;
return response;
}
}
The author says:
For the simplicity’s sake, I implemented it synchronously
But how do I recognize it is synchronous? Is it solely because the method is not defined with async Task, for example:
public async Task<string> GetReleases(string url)
Does that mean that in this HttpClient tutorial, this example is also not asynchronous:
// GET: Student
public ActionResult Index()
{
IEnumerable<StudentViewModel> students = null;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:64189/api/");
//HTTP GET
var responseTask = client.GetAsync("student");
responseTask.Wait();
var result = responseTask.Result;
if (result.IsSuccessStatusCode)
{
var readTask = result.Content.ReadAsAsync<IList<StudentViewModel>>();
readTask.Wait();
students = readTask.Result;
}
else //web api sent error response
{
//log response status here..
students = Enumerable.Empty<StudentViewModel>();
ModelState.AddModelError(string.Empty, "Server error. Please contact administrator.");
}
}
return View(students);
}
So to sum up, my questions are:
Is async programming (in .NET), and async methods, implemented exclusively using async and void/Task/Task?
If not, how else, and if so, how do I recognize "true" asynchronous methods compared to synchronous methods implemented using asychronous principles (like the example above?)
Why then did the above examples use "sync through async", since from everything I've read everyone says to NEVER do that? Are they just bad examples, or for simplicity sake (even so, shouldn't "the correct way" > "simplicity"? Would it be ok to use this in situations where, e.g., I have very simple code and want to avoid threading/deadlock issues, since I'm not comfortable with async programming just yet?
how can I recognize truely async/sync methods?
You can't. Not really. You can spot methods that are potentially async, but little else can be learned without consulting documentation or the implementation of those methods.
So, you can examine a method's return type. If it's void, you don't know much. If it's Task, Task<T>, ValueTask<T> or any other awaitable type1, then the method may be asynchronous. But bear in mind, the method signature may be fixed because the type inherited the method from a base class or it's implementing an interface; So whilst the method has the potential to be async, the actual implementation of that method may be completely synchronous.
Or, the method may have the potential to be asynchronous but may have particular control flows which lead to it behaving synchronously2. These may be e.g. that if certain conditions are true, the method already has the answer, so it returns it straight away. Otherwise it goes off and does something async - as one example.
If the return type isn't awaitable and it's non-void, all you can actually reason about the method is that, at the point at which it returns, it's supplied some value for that return type3. There's no way to reason about any other work that may have been started by that method - only that if it's done something like that, it doesn't intend for you to be able to discover when that work has completed.
If you're looking at the implementation of a method and asking yourself "is this implementation async" then the important thing is to work out what this code makes happen after control is returned back to the caller.
When is control returned back to the caller?
When we hit a return
When we hit an await, maybe
When we hit an await, we only return control back to the caller4 if the awaitable that we're awaiting isn't complete yet. So we have to find out where that awaitable came from and, if it came from calling another method, we have to start again from scratch in considering what that method does.
If the method contains awaits then it's usually safest to say that it's potentially async - but bear in mind the above possibilities about already completed awaitables and early returns.
If it's not async/await, what else might it have done? Well, if it's working with Tasks, it may have created one or more of those tasks to represent it's ongoing work. It may have scheduled more code to run via ContinueWith.
If it's not working with Tasks directly, hasn't called something else that is potentially async, hasn't cause a new Thread to be created and isn't needlessly obfuscated, it's probably synchronous.
Would it be ok to use this in situations where, e.g., I have very simple code and want to avoid threading/deadlock issues, since I'm not comfortable with async programming just yet?
The sync over async patterns shown in the examples in your question are more prone to deadlocks than working with async/await. Why? Because they block the current thread waiting for other things to happen. But the current thread or resources that it has locked may be special - and the actual async tasks that it's invoked may need to gain access to that same thread/resource before they can complete. Classic deadlock.
1Awaitable is one of a number of places where C# uses "duck typing". If there's a method available (instance or extension) called GetAwaiter that returns a type with the right shape, it's awaitable. So despite the fact that you'll probably never see one, be aware that custom awaitables are possible in the language.
2"Hot path" optimizations come to mind.
3And out/ref parameters. Of course, if it has those it won't be an async method implemented via the async/await keywords but it may still have some asynchronous behaviour.
4If we've already yielded control back to the caller during an earlier await, we won't return control back to the caller at later awaits, but we'll be returning it to "something" that isn't our code.
If a method returns a Task or Task<T> (with exception to void in case of event handler) then it can be awaited and hence it can be asynchronous. async keyword is only an indication that it may await somewhere for another awaitable. Based on the control flow, async may return without actually awaiting anything.
Asynchronous programming is not a new thing, it has existed in many forms like callbacks, Invokes etc.
Examples you have provided are not using async await pattern properly. Microsoft has provided naming convention (Async Suffix) and Task<T>, Task as types for async programming. So if you see some method returning Task<T> or Task and Method name has suffix "Async" then you can consider it asynchronous. Although suffix thing is not required by compiler, it helps in differentiating it from its synchronous counterpart. (Read vs ReadAsync)
They are bad examples, those action should be marked as async and all the Async methods should be awaited for result. There can be an exception in some console program where main can't be async.
Please read Stephen Cleary blog on async await
An asynchronous method in C# can return void, Task or Task<T>, where void should be avoided in general because it cannot be awaited.
As a convention asynchronous methods should be called DoSomethingAsync()
The async keyword, however, is an implementation detail and does not belong to the API. This keyword is only required if you use an await in the method body. But that need not be the case. You could simply delegate to another asynchronous method, without the need to mark the method as async and using an await.
So 'true' asynchronous methods should be recognizable by the Async suffix of the method name, however, you can't be sure the implementor actually uses naturally asynchronous operations or even runs synchronously some parts or the whole method.
In the example he made the method synchronously by putting .Result at the end of GetStringAsync

Fire and forget without async void

I have three methods where the first result will be used in the next two methods and no data expected to be return back.
result= await DataAccess.Query(param); //Query
await DataAccess.Create(result);
await DataAccess.Update(result);
Do I really need to use await here?
is it correct to use async void
in create and update function?
what will be the right approach to do
a fire and forget here?
if Im not mentioning async will it be fire
and forget?
what is the significance of async without await if it
only used to run synchronously? I can even achieve that without that keyword.
no data expected to be return back.
What about errors? Do you need to return an error code if an error occurs, or is 200 OK acceptable even if the Create or Update fails?
I'm assuming you'll need an error code. 99.99% of calls do.
Do I really need to use await here?
Well, if you want synchronous methods, then you can just call synchronous APIs. I don't know why you would want that, though.
As a reminder: await has nothing to do with returning to the browser. It has everything to do with using fewer thread pool threads, allowing your server to scale further.
is it correct to use async void in create and update function?
No. Never.
what will be the right approach to do a fire and forget here?
The correct approach is "don't". Fire-and-forget is difficult to do correctly, and in fact since you need an error code, you can't do fire-and-forget.
I write more about fire-and-forget - including why StartNew and Task.Run are invalid solutions - on my blog. Note that the only fully reliable solution (including upgrade scenarios) is the last one (distributed architecture).
what is the significance of async without await if it only used to run synchronously? I can even achieve that without that keyword.
It's running serially (in order), not synchronously (blocking a thread). The benefit of async is to allow greater scalability. For more information, see my intro to async on ASP.NET article.
If you need to call several methods in specific order, but this whole set of functions can run asynchronously, I would do:
Task.Run(() =>
{
result = Function();
Create(result);
Update(result);
});
This will separate group of functions into new thread. Since you are not awaiting this task, it is fire and forget.
If your functions are defined as async, you can wait for them to finish like this:
Task.Run(() =>
{
var task = Function();
task.Wait();
var result = task.Result;
Create(result).Wait();
Update(result).Wait();
});
But when you are not going to benefit from async methods, it will be better to override your methods to run synchronously and use the first code

Categories

Resources