I am implementing a message dispatcher/handler where each handler must implement an interface like Task<Result> HandleAsync(IEvent myevent)
For example:
public async Task<Result> HandleAsync(CustomerChangedEvent ev)
{
await DoSomethingAsync();
...
return myResult;
}
But sometimes I need to run something which is sync only so no await and that as you know will give you a compiler warning. What I have done is to add await Task.CompletedTask; in my code. Works fine AFAIK but is there any downside doing this?
Another alternative is to drop the async but in that case I need to return a Task, right? For example to return Task.FromResult(myResult).
Is there any benefits for one method over another (or different approach), especially from a performance perspective (like is there any substantial cost to declare a method as async. Personally, I prefer the first alternative. For some reason I find return Task.FromResult harder to read and understand even if the first method adds a dummy command.
EDIT:
Sometimes it is maybe better to rethink the logic. "funatparties" commented why run sync code with an async method.
Reason is that I am implementing an outbox message handler where I am processing a queue with different messages to be processed and some have async operations other not. For each type of message I create a handler class which implements an interface.
I want adding handle a new message type I want it to be as few steps as possible. So basically what you do is to create a new handler which implements a specific interface and register the handler with my dispatcher class (which I probably can do automatically as well using Reflection).
The interface require you to implement Task. When reading the queue it will run the HandleAsync method using the registered handler (depending on message type).
A better approach maybe is that the handler can define either an sync or an async method depending on what I need to do.
Actually, I recommend ignoring the compiler warning in this case. Most of the time this compiler warning is useful, so I don't recommend disabling it solution-wide, just here.
The problem with Task.FromResult is that you also have to handle exceptions - catch them and return Task.FromException (or Task.FromCanceled). The problem with await Task.CompletedTask is that it's an unnecessarily expensive NOOP.
So I recommend ignoring the compiler warning. If you have to do this in several places, you can write a simple helper type like this.
I'm guessing the compiler warning you are getting is that you're not using await in an async method.
Using await Task.CompletedTask does nothing useful other than suppress the warning. The await keyword does nothing when it acts on a completed Task. You get no benefit, but there is still the overhead of managing an async method and all the background stuff that has to happen to accommodate it.
If you have to return a Task<Result>, but are not doing anything asynchronously, then drop the async and return Task.FromResult(myResult).
Related
With async turtles all the way down ...
Some of the background research:
Async/Await - Best Practices in Asynchronous Programming
Async
In code I've seen:
Developers wrap code in a Task.Run() upon entering a method and awaiting it to force it to be async or (or older .NET 4.0 TaskFactory.StartNew())
I've personally just left it synchronous (but it partially violates turtles all the down as different branches often are sync)
I've also seen the attempt to use ValueTask to short-circuit the return as async given the nature of ValueTask with a return value being akin to:
return new ValueTask<int>(valueWantToReturn);
Example psudeo code:
public async Task ParentMethodAsync()
{
// ... do something upon entering
int neededValue = SyncNestedDryMethod(); // ** this part **
await _nthLayer.DoSomethingWithRepoAsync(); // ** same concept applies here
// if there is no asyncronous logic required **
// ... do anything else needed
}
public int SyncNestedDryMethod()
{
// ... do something that requires no real async method signature
// declaration because it is straight synchronous logic (covers reusing
// code for DRY purposes, method-level SRP abstraction (includes moving it
// to an abstracted class -- for future readers), etc.)
// I've seen making the method async then awaiting Task.Run() or
// Task.StartFactory.New() inside this (sync changed to async method)
// to try and force it to be async or last line being:
// return new ValueTask<int>(valueWantToReturn);
// but everything above it being only syncronous logic
}
Is there a best practice to be aware of not found addressed in the respective links (or overlooked) or elsewhere which I have not come across to address abstracting synchronous code into new methods (for DRY purposes, SRP, etc.) that do not have the ability to be async or are forced async all the while following async through and through?
Your question isn't entirely clear, but I think you're asking how to run synchronous code in an asynchronous way? If so, the answer is: you can't.
Using Task.Run() doesn't make the code asynchronous. It just runs the code on a different thread and gives you an asynchronous way to wait for that thread to complete. That may be what you need if you just need to get the work off of the current thread. For example, you would use that in a desktop application where you want to get the work off of the UI thread. But this wouldn't help you at all in ASP.NET.
ValueTask is used for cases where the work might be done asynchronously, but also may complete synchronously too. For example, if data is usually returned from an in memory cache, but refreshing that cache is done asynchronously. This is described in detail here. But if the work is always synchronous, then there is no point using ValueTask, or Task or async.
public async Task GetLiveCandleStick(string param)
{
await Clients.All.SendAsync("ReceiveMessage", param);
}
Please consider the above code.
Almost all of the tutorial await Clients.xxx.SendAsync methods. However, I find that it works fine even I take away the await keyword. Then what is the point of using await? (I have seen a thread explaned that await is not meant to "wait until client receive the message...")
Thanks in advance.
By omitting the await keyword, the method would become fire-and-forget; this is almost never the right thing to do, as you would have no way of knowing that the Task had completed.
Another issue is exception handling. If an exception occurs when you call SendAsync, it is placed on the Task rather than being thrown directly, and would simply be garbage collected without using await.
Having said this, if your GetLiveCandleStick method is a simple wrapper as you suggest, it would be slightly more efficient to simply return the Task from SendAsync rather than create a new one using async:
public Task GetLiveCandleStick(string param)
{
return Clients.All.SendAsync("ReceiveMessage", param);
}
In this case only, you don't need to use await - nothing else is happening after SendAsync so there's no need to await. Awaiting on GetLiveCandleStick would behave the same as awaiting on SendAsync. You could convert this method to :
public Task GetLiveCandleStick(string param)=> Clients.All.SendAsync("ReceiveMessage", param);
Tutorials use await because quite often there is code after SendAsync, that should be executed after SignalR enqueues the message.
You may want to add error handling in case SignalR throws for example, or ensure a Begin message is enqueued after an End message in a tight loop. Having an await even for a single statement method can be useful for debugging too.
Finally, good tutorials shouldn't introduce unrelated concepts as this can easily lead to confusion. A SignalR tutorial isn't the best place for explaining the await state machine, or when await can be skipped. Unfortunately, too many examples in learn.microsoft.com try to put everything into a single page, resulting in quite a bit of confusion.
The keyword "await" is for async methods. It's smarter than "wait", it's async wait!
This means that wait the return of message during exec the code until the result is necessary used. So You don't have to use Thread.Wait in a line of code, but the compiler place the wait in the right position. In this case the method that call the await is async, so the wait of Clients.All.SendAsync is out of function.
I have a large scale C# solution with 40-ish modules.
I'm trying to convert a service used solution-wide from synchronous to asynchronous.
the problem is I can't find a way to do so without changing the signature of the method.
I've tried wrapping said asynchronous desired operation with Task but that requires changing the method signature.
I've tried changing the caller to block itself while the method is operating but that screwed my system pretty good because it's a very long calling-chain and changing each of the members in the chain to block itself is a serious issue.
public SomeClass Foo()
{
// Synchronous Code
}
Turn this into:
public SomeClass Foo()
{
//Asynchronous code
}
whilst all callers stay the same
public void DifferentModule()
{
var class = Foo();
}
Any implementation that fundamentally changes something from sync to async is going to involve a signature change. Any other approach is simply not going to work well. Fundamentally: async and sync demand different APIs, which means: different signatures. This is unavoidable, and frankly "How to convert synchronous method to asynchronous without changing it's signature?" is an unsolvable problem (and more probably: the wrong question). I'm sorry if it seems like I'm not answering the question there, but... sometimes the answer is "you can't, and anyone who says you can is tempting you down a very bad path".
In the async/Task<T> sense, the most common way to do this without breaking compatibility is to add a new / separate method, so you have
SomeReturnType Foo();
and
Task<SomeReturnType> FooAsync(); // or ValueTask<T> if often actually synchoronous
nothing that Foo and FooAsync here probably have similar but different implementations - one designed to exploit async, one that works purely synchronously. It is not a good idea to spoof one by calling the other - both "sync over async" (the synchronous version calling the async version) and "async over sync" (the async version calling the sync version) are anti-patterns, and should be avoided (the first is much more harmful than the second).
If you really don't want to do this, you could also do things like adding a FooCompleted callback event (or similar), but : this is still fundamentally a signature change, and the caller will still have to use the API differently. By the time you've done that - you might as well have made it easy for the consumer by adding the Task<T> API instead.
The common pattern is to add an Async to the method name and wrap the return type in a Task. So:
public SomeClass Foo()
{
// Synchronous Code
}
becomes:
public Task<SomeClass> FooAsync()
{
// Asynchronous Code
}
You'll end up with two versions of the method, but it will allow you to gradually migrate your code over to the async approach, and it won't break the existing code whilst you're doing the migration.
If you desperately need to do this, it can be achieved by wrapping the Synchronous code that needs to become Asynchronous in a Task this can be done like this:
public SomeClass Foo()
{
Task t = Task.Run(() =>
{
// Do stuff, code in here will run asynchronously
}
t.Wait();
// or if you need a return value: var result = t.Wait();
return someClass;
// or return result
}
Code you write inside the Task.Run(() => ...) will run asynchronously
Short explanation: with Task t = Task.Run(() => ...) we start a new Task, the "weird" parameter is a Lambda expression, basically we're passing a anonymous Method into the Run method which will get executed by the Task
We then wait for the task to finish with t.Wait();. The Wait method can return a value, you can return a value from an anonymous method just like from any method, with the return keyword
Note: This can, but should not be done. See Sean's answer for more
I have a C# Windows Store app with a streamsocket listener running in a task waiting for commands to come in over the network. I need to make sure each command is fully processed before doing the next one.
The listener takes a raw message and does
await ProcessMessage(message);
which is
private async Task ProcessMessage(string message, string optionalFlags = "")
Which parses the message and calls one of many methods, i.e.
ProcessCommandXYZ(parameters);
This seems to work, but in the async task ProcessMessage line I get a CS1998 "async method lacks 'await'" warning, and searching says if you get this message you're probably not using async correctly.
Is my approach correct and can I ignore this warning, or is there a better way to do this?
Update
I realize a lot of my problem is one of the methods is updating the state which is bound to a listview, so it's in a UI dispatcher and makes it get out of sync and I was awaiting it's ProcessCommandABC(). Since it's just the one method I believe I can optimize if that's best and don't await the one method?
The purpose of using async is so that you can use the keyword await in that function/method. Because the ProcessMessage method is not doing any awaits inside it, the compiler is giving you that warning. The solution is simple: remove the async from ProcessMessage. The use of await by a caller does not require that the method it is calling be declared with async. The method just needs to be returning a Task or Task<T>.
As mentioned by #Mayoor, the lack of awaits in the ProcessMessage suggests it is doing synchronous work, in which case it shouldn't be async. Declaring a method as async does not make it asynchronous it simply allows you to use await inside it to wait for asynchronous work to complete.
if the work is synchronous, you can run it in the background using Task.Run which you can await. So one possible solution is to make your ProcessMessage method synchronous and then just call
await Task.Run(() => ProcessMessage(...));
You can learn more about async-await best practices in this article.
I'm looking at some code written a while back that is making me very nervous. The general shape of the methods in questions is like this;
public Task Foo(...){
SyncMethod();
SyncMethod();
...
return AsyncMethod();
}
I realize I can just mark the method async and do an await on the last call, but...do I have to? Is this safe to use as is? The sync methods that are called before the last async method do not have asynchronous alternatives and the Foo method does not care about the result of the AsyncMethod, so it looks like it's ok to just return the awaitable to the caller and let the caller deal with it.
Also, FWIW, the code in question might be called from a thread that's running with an active ASP.NET context, so I'm getting that tingling feeling in my brain that there's some invisible evil that I'm not seeing here?
I realize I can just mark the method async and do an await on the last call, but...do I have to?
Actually, if you did this, the only change that it would have is that exceptions thrown by either of those synchronous methods would be wrapped into the returned Task, while in the current implementation the method would throw without ever successfully returning a Task. The actual effect of what work is done synchronously and what work is done asynchronously is entirely unaffected.
Having said that, both of the options you've mentioned are worrisome. Here you have a method that appears to be asynchronous, meaning someone calling it expects it to return more or less right away, but in reality the method will run synchronously for some amount of time.
If your two synchronous methods are really fast and as a result, you're confident that this very small amount of synchronous work won't be noticeable to any of your callers, then that's fine. If, however, that work will (even potentially) take a non-trivial amount of time to solve, then you have a problem on your hands.
Having actually asynchronous alternatives for those methods would be best, but as a last resort, until you have a better option, often the best you can manage to do is to await Task.Run(() => SyncMethod()); for those methods (which of course means the method now needs to be marked as async).