Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I update my API to use the async keyword without using await for all callers

I am trying to port some TcpClient dependant code to .net 4.5, using StreamSocket and DataReader instead.

I have a function named ReadLine() which is used everywhere. By using DataReader in the body (LoadAsync()) of this code, my method is forced to be marked with the async keyword.

The chain reaction is as follows: Now I have hundreds of places where I have to add async to calling methods and apply await to underlying async method calls.

This leads me to my next question... Is there an easy way to wrap ReadLine() so that calling methods are not aware that it's an asynchronous method, so that I don't have to change the rest of my code?

Also... I often use this method call in a loop, from multiple places. If these methods are now marked async, i'm afraid I might be reading data off a stream when I shouldn't be, which will cause all sorts of nightmares. Is it a problem or am I thinking too far ahead?

like image 833
c0D3l0g1c Avatar asked Jan 06 '13 19:01

c0D3l0g1c


People also ask

Can I use async function without await?

In this way, an async function without an await expression will run synchronously. If there is an await expression inside the function body, however, the async function will always complete asynchronously. Code after each await expression can be thought of as existing in a .then callback.

How do you wait for async to finish without await?

Because async functions are Promises under the hood, we can run both asyncThing1() and asyncThing2() in parallel by calling them without await . Then we can use await and Promise. all , which returns an array of results once all Promises have completed.

What happens if I call an async function without await?

Marking a function as async without using await or returning a value inside it can lead to an unintended promise return and a larger transpiled output. Often the function can be synchronous and the async keyword is there by mistake.

What happens if await is not used?

If you forget to use await while calling an async function, the function starts executing. This means that await is not required for executing the function. The async function will return a promise, which you can use later.


2 Answers

Also... I often use this method call in a loop, from multiple places. If these methods are now marked async, i'm afraid I might be reading data off a stream when I shouldn't be, which will cause all sorts of nightmares. Is it a problem or am I thinking too far ahead?

If you always use await whenver you call *Async methods, then your async methods will act just like synchronous methods (except they won't block). So using await in a loop will work just like you expect.


async does indeed "grow" through the code base. I usually think of this as similar to the old story about "turtles all the way down"; others have called it a "zombie virus".

I describe the deadlock situation in detail on my blog. As I state there, the best option is to allow async to grow.

If you must create a synchronous wrapper for an asynchronous method, see Stephen Toub's advice. You can use Task.Result, but you need to do two things:

  • Use ConfigureAwait(false) everywhere. This will sidestep the deadlock situation.
  • Be aware that Result has different error handling semantics.

For your particular example, something like this should suffice:

private async Task<string> ReadLineAsync()
{
  ... // *Every* await in this method and every method it calls
      // must make use of ConfigureAwait(false).
}

public string ReadLine()
{
  try
  {
    return ReadLineAsync().Result;
  }
  catch (AggregateException ex)
  {
    ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
    throw;
  }
}

Please carefully consider the complexity before choosing a mixed synchronous/asynchronous code base. It's not as easy as it first appears.

P.S. Generally speaking, TCP/IP code should all be asynchronous anyway. It's usually a good idea to have a continuous asynchronous read going on a socket.

like image 101
Stephen Cleary Avatar answered Sep 20 '22 15:09

Stephen Cleary


Make a ReadLineAsync function and a ReadLine function.
In the ReadLine function you can call ReadLineAsync like this:

var readLineTask = ReadLineAsync(); 
readLineTask.Wait() 
like image 30
roeland Avatar answered Sep 21 '22 15:09

roeland