Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Async when also needing support for synchronous call

I'm in a situation where we have some code that is run by user input (button click), that runs through a series of function calls and result in generating some data (which is a quite heavy operation, several minutes). We'd like to use Async for this so that it doesn't lock up the UI while we're doing this operation.

But at the same time we also have a requirement that the functions will also be available through an API which preferably should be synchronous.

Visualization/Example (pseudo-code):

public async void Button_Click() // from UI context
{
  await instanceOfClassA.FuncA();

  // some code
}

public async Task ClassA.FuncA()
{
  await instanceOfClassB.FuncB()

  // some code
}

public async Task ClassB.FuncB()
{
  await instanceOfClassC.SomeHeavyFunc()

  // some code
}

public async Task ClassC.SomeHeavyFunc()
{
  // some heavy calculations
}


// Also need to provide a public synchronous API function
public void SomeClass.SynchronousAPIFunc()
{
  // need to call differentInstanceOfClassB.FuncB()
}

Is there a way to make it so that the public API function does the waiting for the async operation internally?

EDIT: In this post, user Rachel provides two answers to the question. Both seem interesting, though I'm unsure which one would offer the least amount of risk/side effects.

EDIT2: I should note that we're using .NET v4.6.1.

Thanks in advance.

like image 815
OneRaccoonToRuleThemAll Avatar asked Dec 10 '22 00:12

OneRaccoonToRuleThemAll


1 Answers

The problem with making "synchronous" versions of your methods that just call the asynchronous versions is that it can cause deadlocks, especially if the person calling this code is not aware that this is what is happening.

If you really want to make synchronous versions, then follow Microsoft's lead and write completely new methods that do not use any asynchronous code. For example, the implementation for File.ReadAllLines() doesn't use any of the same code as File.ReadAllLinesAsync().

If you don't want to do that, then just don't provide synchronous versions of your methods. Let the caller make the decision on how to deal with it. If they want to block synchronously on it, then they can mitigate the risk of deadlock.

like image 132
Gabriel Luci Avatar answered Dec 25 '22 14:12

Gabriel Luci