Async all the way down? - c#

Trying to understand the new async/await pattern, I have one question which I can't find an answer to, namely if I should decorate my methods with async, if I intend to call those methods from other async functions, or just return Tasks where appropriate?
In other words, which of these classes A, B or C is best, and why?
class A<T>
{
public async Task<T> foo1() //Should be consumed
{
return await foo2();
}
public async Task<T> foo2() //Could be consumed
{
return await foo3();
}
private async Task<T> foo3() //Private
{
return await Task.Run(...);
}
}
class B<T>
{
public async Task<T> foo1() //Should be consumed
{
return await foo2();
}
public async Task<T> foo2() //Could be consumed
{
return await foo3();
}
private Task<T> foo3() //Private
{
return Task.Run(...);
}
}
class C<T>
{
public async Task<T> foo1() //Should be consumed
{
return await foo2();
}
public Task<T> foo2() //Could be consumed
{
return foo3();
}
private Task<T> foo3() //Private
{
return Task.Run(...);
}
}
It seems redundant to overdecorate methods so I naturally lean toward C, but at the same time it feels somewhat awkward to work with Task<T> unless you use the await keyword.

Both versions work effectively the same, the only difference is that when you use await here, you get some performance penalty (because the state machine must be set up and a continuation will most likely be used).
So, it comes down to a tradeoff: Do you want your methods to be somewhat more efficient at the cost of being slightly less readable? Or are you willing to sacrifice performance for readability?
Usually, I would advise you to go for readability first and only focus on performance if profiling tells you it's worth it. But in this case, I think the increase in readability is small, so I would probably not use await.
Also note that your class C still doesn't go far enough: foo1() also doesn't need await.

The async in the signature is there to allow the compiler to create the state-machine rewriting of the contained code that is necessary to implement the await semantics in the general case.
Your example is exactly the special case where you do not need that rewriting: The asynchronous operation is the last thing happening within a method. That kind of method is already possible and valid in .NET4.0. This compatibility might be one reason to avoid async when you do not need it.

Related

Will ValueTask still be beneficial if it depends on a method that returns Task?

Using the following methods as an example:
public async ValueTask<int> MyMethod() {
return await GetMyIntegerWithTask();
}
public async Task<int> GetMyIntegerWithTask() {
if (/*in hot path*/) {
return await SynchronousMethodThatUsesTask();
}
return await AsynchronousMethodThatUsesTask();
}
public Task<int> SynchronousMethodThatUsesTask() {
int value = new Random().Next();
return Task.FromResult(value);
}
public async Task<int> AsynchronousMethodThatUsesTask() {
//some asynchronous calculation
}
Does using ValueTask as the return type of MyMethod still have the advantages associated with ValueTask because I expect that most of the time my code will execute synchronously (even though the synchronous method I'm depending on returns Task rather than ValueTask)?
Does using ValueTask as the return type of MyMethod still have the advantages associated with ValueTask because I expect that most of the time my code will execute synchronously (even though the synchronous method I'm depending on returns Task rather than ValueTask)?
The performance benefits of ValueTask are minor, unless you are calling this very often. That said, yes, ValueTask will at the very least avoid a Task allocation, and in the synchronous case also avoids boxing the state machine struct onto the heap.
It would be better if both GetMyIntegerWithTask and SynchronousMethodThatUsesTask also use ValueTask<int>, but even without that MyMethod can use ValueTask<int> to avoid some allocations, at least.

Is there any way to know if a method is running being awaited from within the method?

I'm a university student but, since I like programming, I try to create a library of code that's been useful to me (something like a code base).
In the process of doing this, I started designing/writing an asynchronous method that's about to be used for interlocking a variable. My goal is to produce different result when this method is being awaited (runs synchronously) and when it isn't.
An example could be the following:
private int _lock;
public async Task<bool> Lock()
{
if (method_is_not_being_awaited)
return Interlocked.Exchange(ref _lock, 1) == 0;
while (0 != Interlocked.Exchange(ref _lock, 1)) {}
return true;
}
Is there any way to achieve such result? If yes, how?
ps: I know that I could make 2 different methods bool lock() and async Task<bool> lockAsync() but, that's not what I ask for
No, it is not possible to do what you want because method must return value before any operation on result (including await) can be performed. It is not specific to async methods but rather how all code behaves in C# (and pretty much any other language).
On other hand it is pretty easy to do something that very close to what you ask - synchronously return value as soon as one tries to await the result of the method: await is essentially just call to GetAwaiter on the result and you can wire it up to alter state of your method.
Note that you can't really know what to do if method ever awaited anyway - so while you can act at moment when await is called you really can't know in advance if you should start asynchronous processing. So the best you can achieve is to do nothing in synchronous part, start asynchronous processing anyway and instantly return result when await is called (aborting/ignoring asynchronous part of the method).
Details on implementing class that can be used as result can be found in https://www.codeproject.com/Articles/5274659/How-to-Use-the-Csharp-Await-Keyword-On-Anything and https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/task-asynchronous-programming-model.
Skeleton code below shows how to implement method that does nothing unless await is called:
class MyTask
{
public MyAwaitable GetAwaiter()
{
return new MyAwaitable();
}
}
class MyAwaitable : INotifyCompletion
{
public bool IsCompleted
{
get { return true; }
}
public int GetResult()
{
return 42; // this is our "result" from method.
}
public void OnCompleted (Action continuation)
{
// just run instantly - no need to save callback as this one is
// always "completed"
continuation();
}
}
MyTask F()
{
// if your really want you can start async operation here
// and somehow wire up MyAwaitable.IsComplete to terminate/abandon
// asynchronous part.
return new MyTask();
}

What is async in System.Data.Common.DbDataReader.ReadAsync?

I am looking at the code for DbDataReader (also DbCommand) at MS reference and can't figure out what is async in ReadAsync() method.
virtual public Task<bool> ReadAsync(CancellationToken cancellationToken) {
if (cancellationToken.IsCancellationRequested) {
return ADP.CreatedTaskWithCancellation<bool>();
}
else {
try {
return Read() ? ADP.TrueTask : ADP.FalseTask;
}
catch (Exception e) {
return ADP.CreatedTaskWithException<bool>(e);
}
}
}
The ReadAsync method just calls Read method and returns a complete task.
Doesn't this block the calling thread the same way as calling Read directly?
I have noticed the same pattern in DbCommand ExecuteReaderAsync and other methods. They just call the sync versions and return completed Tasks.
What am I missing here?
UPDATE: I did not miss anything, as #PeterBons explained nicely (also in the documentation). I still don't like it, but that's my problem.
You are looking at a virtual method in an abstract class. If you want (future) implementations to be able to do some truly async work you will have to define a method signature that allows that. So it should return a Task or Task<T>. Remember that just using a Task does not make anything asynchronous, it makes it awaitable.
The use of the Task<bool> return type in this example virtual method is to facilitate other classes that derive from DbDataReader to provide real async behavior in their implementation of ReadAsync.
For example, a truly async implementation could do something like
class TrueAsyncReader : DbDataReader
{
...
public override async Task<bool> ReadAsync(CancellationToken cancellationToken)
{
...
return await ReadFromDbAsync();
}
}
As you can see you can now have async and non async implementations, without having to alter the method signature.
Since you can easily call synchronous code from an async method this is the way to go. Calling async code from a synchronous method is a nog go.
for non async implementations that need to return a task you can return something like Task.FromResult<T> or Task.CompletedTask. This will not block.
See also await Task.CompletedTask for what?
To summarize: the default implementation does not do anything async but derived classes can without having to change the method signature.

How do you handle a 3rd party interface returning Task if you don't have any async code? [duplicate]

This question already has answers here:
How to implement interface method that returns Task<T>?
(4 answers)
Closed 6 years ago.
I am working with a third-party dll which exposes methods which return Task and Task<T>. I don't have any control over this assembly or the interface, and I assume the author assumed everything would need to be async since the naming of the methods are *Async() as shown below.
Given that, how do I properly implement the interface if I don't actually have any asynchronous code running?
public interface IFoo
{
Task DoWorkAsync();
Task<int> GetValueAsync();
}
My attempt was the following:
public class FooBar : IFoo
{
public async Task DoWorkAsync()
{
// Do Some Work
await Task.Yield();
}
public async Task<int> GetValueAsync()
{
// Do Some Work
var result = ...;
return Task.FromResult(result);
}
}
Additionally:
Was the author correct in exposing only methods that returned Task/Task<T>?
Was the author correct in suffixing method names with *Async()? Code analysis doesn't complain if I write an async method without appending Async to the name.
If you don't have async work to do don't include the async keyword. Your GetValueAsnyc function was almost correct, you just needed to drop the async. For your DoWorkAsync you should just not mark the method async and return a completed task.
public class FooBar : IFoo
{
public Task DoWorkAsync()
{
// Do Some Work
//If you can use .NET 4.6
return Task.CompletedTask;
//For older versions, the thing you pass in does not matter, I like to use bool.
return Task.FromResult(false);
}
public Task<int> GetValueAsync()
{
// Do Some Work
var result = ...;
return Task.FromResult(result);
}
}
However, if your code is slow and you end up blocking the UI for a long period of time I would consider looking in to if you can re-write your code as actually being async or perhaps wrapping the code in to a background thread, but I would only do a background thread if it was a last resort.

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