Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
I read alot about async/await, but I still have some lack in understanding the following situation.
My question is, should I implement my "wrapper" methods as in DoSomething() or like in DoSomethingAsync().
So what's better (and why): Do I use await in wrapper methods or return the Task directly?
public static async void Main()
{
await DoSomething();
await DoSomethingAsync();
}
private static Task DoSomething()
{
return MyLibrary.DoSomethingAsync();
}
private static async Task DoSomethingAsync()
{
await MyLibrary.DoSomethingAsync().ConfigureAwait(false);
}
public class MyLibrary
{
public static async Task DoSomethingAsync()
{
// Here is some I/O
}
}
Async/Await are still relatively new, but there are some good practices to help clarify an API. The basics are this:
A method declaring itself as async means it is expecting to await later on
async implicitly creates a Task for you.
await is like a bookmark. The application resumes where the await keyword was used.
You cannot await anything that is not IAwaitable (most commonly a Task) (citation)
In an application where there are both asynchronous calls and synchronous calls, we've adopted a naming convention:
async calls return Task or Task<T> and append the word Async to the end of the name.
Synchronous calls (the default) simply work like any method does and there is no special convention.
Often, there can be two methods which do the same thing, but one is synchronous and the other not. You can either implement it two different ways, or you can wrap one with the other. It really depends on your needs and what is going to give you the more responsive application.
In the example above, the proper way to handle async and normal method calls would be for MyLibrary to expose two methods. The example would be like this:
public static class MyLibrary
{
public static void DoSomething()
{
// do some work
}
public static async Task DoSomethingAsync()
{
// do similar work but use async API,
// can also simply call DoSomething().
}
}
// In another part of code would be called like this:
public static async Task BiggerMethod()
{
MyLibrary.DoSomething();
await MyLibrary.DoSomethingAsync();
}
What you want to avoid is wrapping an async method with a regular method. As soon as you work with the Task directly, you lose all benefits of async and await and you introduce places where your code can deadlock.
Berin's answer is good but does not explicitly address the particular case in your question, which is the following example:
1: Returning the Task directly
private static Task DoSomething()
{
return MyLibrary.DoSomethingAsync();
}
2: Awaiting the Task and returning the result
private static async Task DoSomethingAsync()
{
await MyLibrary.DoSomethingAsync().ConfigureAwait(false);
}
In this case, the only difference between returning the Task directly and awaiting the Task and returning the response is that - in the latter case - a state machine must be created by the framework to manage the starting, suspending and continuing of the method awaiting the Task. This incurs some performance overhead.
Generally speaking, if you can just return a Task and allow it to be awaited higher up, you should. In most (but certainly not all) real cases, however, this won't be possible as you will want to perform some processing of the result before returning (and this is exactly what async/await helps you to achieve).
There's no difference in case of one-liners.
But in case of at least two-async-liners, e.g.:
public static async void Main()
{
await DoSomething();
await DoSomethingAsync();
}
private static Task DoSomethingTwice()
{
var do1 = MyLibrary.DoSomethingAsync();
// when you await DoSomethingTwice, next line's reached
// when do1 task may not be completed
var do2 = MyLibrary.DoSomethingAsync();
// return what???
// how to combine them?
// okay, you can do that
return Task.WhenAll(do1, do2)
}
private static async Task DoSomethingTwiceAsync()
{
await MyLibrary.DoSomethingAsync().ConfigureAwait(false);
// when you await DoSomethingTwiceAsync, next line's reached
// when prev-line task is completed
await MyLibrary.DoSomethingAsync().ConfigureAwait(false);
}
public class MyLibrary
{
public static async Task DoSomethingAsync()
{
// Here is some I/O
}
}
Summary:
if you have to organize you method as a chain of sequential asyncronous peaces of work: doAsync1() -> doAsync2() -> doAsync3(),
i.e. every next peace needs complete result of previous one, then you should await every call as:
async Task DoAsync()
{
await doAsync1();
await doAsync2();
await doAsync3();
}
but you cannot use await in non-async methods. So your cannot do it in your Task DoSomething() style, only as async Task DoSomethingAsync().
if there's no asyncronous chain - you can do whatever you want as in my first example above
Related
I have an async method which will load some info from the database via Entity Framework.
In one circumstance I want to call that code synchronously from within a lock.
Do I need two copies of the code, one async, one not, or is there a way of calling the async code synchronously?
For example something like this:
using System;
using System.Threading.Tasks;
public class Program
{
public static void Main()
{
new Test().Go();
}
}
public class Test
{
private object someLock = new object();
public void Go()
{
lock(someLock)
{
Task<int> task = Task.Run(async () => await DoSomethingAsync());
var result = task.Result;
}
}
public async Task<int> DoSomethingAsync()
{
// This will make a database call
return await Task.FromResult(0);
}
}
Edit: as a number of the comments are saying the same thing, I thought I'd elaborate a little
Background: normally, trying to do this is a bad idea. Lock and async are polar opposites as documented in lots of places, there's no reason to have an async call in a lock.
So why do it here? I can make the database call synchronously but that requires duplicating some methods which isn't ideal. Ideally the language would let you call the same method synchronously or asynchronously
Scenario: this is a Web API. The application starts, a number of Web API calls execute and they all want some info that's in the database that's provided by a service provider dedicated for that purpose (i.e. a call added via AddScoped in the Startup.cs). Without something like a lock they will all try to get the info from the database. EF Core is only relevant in that every other call to the database is async, this one is the exception.
You simply cannot use a lock with asynchronous code; the entire point of async/await is to switch away from a strict thread-based model, but lock aka System.Monitor is entirely thread focused. Frankly, you also shouldn't attempt to synchronously call asynchronous code; that is simply not valid, and no "solution" is correct.
SemaphoreSlim makes a good alternative to lock as an asynchronous-aware synchronization primitve. However, you should either acquire/release the semaphore inside the async operation in your Task.Run, or you should make your Go an asynchronous method, i.e. public async Task GoAsync(), and do the same there; of course, at that point it becomes redundant to use Task.Run, so: just execute await DoSomethingAsync() directly:
private readonly SemaphoreSlim someLock = new SemaphoreSlim(1, 1);
public async Task GoAsync()
{
await someLock.WaitAsync();
try
{
await DoSomethingAsync();
}
finally
{
someLock.Release();
}
}
If the try/finally bothers you; perhaps cheat!
public async Task GoAsync()
{
using (await someLock.LockAsync())
{
await DoSomethingAsync();
}
}
with
internal static class SemaphoreExtensions
{
public static ValueTask<SemaphoreToken> LockAsync(this SemaphoreSlim semaphore)
{
// try to take synchronously
if (semaphore.Wait(0)) return new(new SemaphoreToken(semaphore));
return SlowLockAsync(semaphore);
static async ValueTask<SemaphoreToken> SlowLockAsync(SemaphoreSlim semaphore)
{
await semaphore.WaitAsync().ConfigureAwait(false);
return new(semaphore);
}
}
}
internal readonly struct SemaphoreToken : IDisposable
{
private readonly SemaphoreSlim _semaphore;
public void Dispose() => _semaphore?.Release();
internal SemaphoreToken(SemaphoreSlim semaphore) => _semaphore = semaphore;
}
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.
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.
This question already has answers here:
At the end of an async method, should I return or await?
(2 answers)
Any difference between "await Task.Run(); return;" and "return Task.Run()"? [duplicate]
(4 answers)
Closed 5 years ago.
async void Main()
{
var cp=new ConentProxy();
Console.WriteLine(await cp.GetAsync());
Console.ReadLine();
}
// Define other methods and classes here
public class HttpsContentProvider : IContentProvider
{
private static HttpClient hc=new HttpClient();
//**#No.1**
public async Task<string> GetAsync() {
return await hc.GetStringAsync("https://www.stackoverflow.com").ConfigureAwait(false);
}
}
public class DefaultContentProvider : IContentProvider
{
//**#No.2**
public async Task<string> GetAsync()
{
return await Task.FromResult("Default").ConfigureAwait(false);
}
}
public interface IContentProvider
{
Task<string> GetAsync();
}
public class ConentProxy : IContentProvider
{
public static int conentType = int.Parse(ConfigurationManager.AppSettings["UseHttps"] ?? "0");
//**#No.3**
public async Task<string> GetAsync()
{
switch (conentType)
{
case 0:return await new HttpsContentProvider().GetAsync();
default:return await new DefaultContentProvider().GetAsync();
}
}
}
In the code above, there are three "async" with a "#No." tag ahead. They are all short methods just one or two lines only.
They can be await without "async" as they return Task or Task<T>.
It could be far more than 2 call layer on the No.1 tag in actual code. So there will be many "async"s cascade.
Should I add an "async" to a short method or not ? As I know, there is cost for async and await;
Especilly the No.3, it's just a proxy method. The real operation method will block is the HttpClient.GetStringAsync at #No.1.
=====================================================
After reading the first answer from #dustinmoris, I found the following code in HttpClient class. It makes me confused that there is no async and no ConfigureAwait(false), which is the same as other methods of HttpClient
public Task<byte[]> ReadAsByteArrayAsync()
{
this.CheckDisposed();
TaskCompletionSource<byte[]> tcs = new TaskCompletionSource<byte[]>();
this.LoadIntoBufferAsync().ContinueWithStandard((Action<Task>) (task =>
{
if (HttpUtilities.HandleFaultsAndCancelation<byte[]>(task, tcs))
return;
tcs.TrySetResult(this.bufferedContent.ToArray());
}));
return tcs.Task;
}
Technically there are much better explanations, but for beginners the rule of thumb should be:
Use async when
a library offers you an async option, then generally it is doing something which will hugely benefit from async (HttpClient, StreamReader, etc.)
if because of 1. you had to use async somewhere, then you have to use async all the way up, because every higher level method which calls into your async method is now essentially also async.
if 1. and 2. don't apply, don't turn a method into async otherwise
The length of a method has nothing to do with it, actually the smaller your methods the better, because it is a sign of good coding practices.
The additional cost of async/await, even when it is literally all over your code is normally outweighed by the gains you get when you followed rule 1. and 2.
Now to answer the question if you have to decorate a method with async if you can just return the task directly:
Awaiting tasks: Return task or await if no code after await
At the end of an async method, should I return or await?
I have a problem where async methods are being called in the code without await in front of it. Is there a way to find all the awaitable methods that do not have await?
Edit - I'm particularly concerned with the scenario where multiple async methods are being called (ignoring the return values), but only one has await which is enough to make Visual Studio not warn about it.
If you use ReSharper and turn solution-wide analysis on, your methods that are returning tasks that are not being awaited will have the Task portion of the method signature grayed out due to "return value is not used." The caveat here is that this will only find methods that are not being awaited anywhere in your solution; the warning will go away after one or more usages are updated to await (or use/reference the Task).
If you're looking for async methods that don't contain an await call (meaning they don't need to be labeled async), ReSharper will tell you about that too in a similar fashion.
class AClass
{
public async void Foo() //async grayed out
{
DoSomethingAsync();
Console.WriteLine("Done");
}
public Task<bool> DoSomethingAsync() //Task<bool> grayed out
{
return Task.Run(() => true);
}
}
Note this will not work if you have code that looks like this:
class AClass
{
public async void Foo()
{
bool b = DoSomethingAsync().Result;
Console.WriteLine("Done");
}
public Task<bool> DoSomethingAsync()
{
return Task.Run(() => true);
}
}
The async keyword, if present, will still be flagged, which means you can probably figure out pretty quickly a Task is not being awaited, but if the calling method is not marked async you are out of luck.