Refactoring old code to use async keyword

Viewed 247

I have started refactoring old code to become Async. If the method is not straight forward to async then i'm copying the old method and I create a new MethodAsync(), and then i just upgrade one by one client to use the new async method when I can.

But I would instead like to avoid creating this duplicate methods. So i'm wondering if there is performance issues with the following two scenarios:

  1. UPDATE: Ignore point 1

  2. Method is async with await keyword(s). But the client is still not async so it is using .Result :- forcing it to sync behavior. Is this way of "forcing" sync behavior more bad than calling a method that does not use async keyword?

Update: The Async State machine created with the async keyword would introduce overhead. So another question would be how much impact does that have, keep in mind this project is huge in the numbers of several thousand methods.

And 4:- Are there any other factors than the creation of Async state machine that comes to play with the performance while the methods are not yet true async?

2 Answers

But the client is still not async so it is using .Result :- forcing it to sync behavior. Is this way of "forcing" sync behavior more bad than calling a method that does not use async keyword?

It's generally considered an antipattern. The main reason is that it can cause deadlocks, depending on the client.

Update: The Async State machine created with the async keyword would introduce overhead. So another question would be how much impact does that have, keep in mind this project is huge in the numbers of several thousand methods.

Any overhead from the async keyword is minimal, compared to the overhead of blocking threads on asynchronous code.

I would instead like to avoid creating this duplicate methods.

I recommend reading my article on Brownfield Async Development; in particular, the "boolean argument hack" is one I've used with some success in this scenario.

Is this way of "forcing" sync behavior more bad than calling a method that does not use async keyword?

As mentioned by @mong Zhu, this risks causing deadlocks. Say that the method is awaiting some work that needs to be done on the main thread, calling .Result on the mainthread will prevent the main-thread from being used, effectivly deadlocking the application.

The Async State machine created with the async keyword would introduce overhead. So another question would be how much impact does that have

This is almost impossible to answer since performance spans multiple orders of magnitude. The overhead should be small when doing things Async/await is intended for, i.e. IO operations or compute bound operations sufficiently slow for the user to notice. The general recommendation is as always: measure.

Are there any other factors than the creation of Async state machine that comes to play with the performance while the methods are not yet true async

The state machine is simply a hidden class with a large switch statement. I have not measured this, but I suspect the overhead of the state machine is smaller than scheduling work on another thread. However, marking a method as async is pointless unless you are not using await. If you are returning tasks but not using await you can either:

  1. Return the task returned from another method. Say that you do some initial work and call ReadToEndAsync that returns a Task<string>, just return the task as is.
  2. use Task.FromResult(myObject) to create a completed task, or Task.CompletedTask;
  3. Edit: Return a ValueTask instead, this is either a task or a TResult. Since this is a struct there is very little overhead to create one.
Related