There is a console application that accepts incoming connections, reads a command, executes it, and returns a response (or executes without an answer). The scope of the application is as follows:

1) Http requests.

2) Database requests.

3) Sending commands by socket to another console application.

I rummaged through many articles on the Internet, where it is written that using ConfigureAwait (false) is unacceptable in a GUI application, since it requires the original context after the asynchronous function. I have a console application in which, as I understand it, it does not matter in what context the function will continue to be performed. Do I think correctly? Can the ubiquitous use of ConfigureAwait (false) in my application turn sideways? And more specifically:

1) Is deadlock possible?

2) Increased system load / reduced performance.

3) Execution of asynchronous functions not in a predetermined order (I read it in one article).

4) Or any other problem about which I do not know.

Sample code from the program:

private async Task UpdateUserBalance(int id, decimal amount) { Transaction transaction = await DataBase.StartTransactionAsync().ConfigureAwait(false); try { UserModel user = await UserModel.FindAsync(id, transaction).ConfigureAwait(false); user.balance += amount; await user.Update(transaction).ConfigureAwait(false); await transaction.CommitAsync().ConfigureAwait(false); } catch (Exception e) { await transaction.RollbackAsync().ConfigureAwait(false); } finally { transaction.Dispose(); } } 

There are also async void functions that cause mistrust towards deadlocks. Example:

 class TimerClass { private Timer _timer; // using System.Timers; public TimerClass() { _timer = new Timer(5 * 1000); _timer.Elapsed += Callback; _timer.AutoReset = true; _timer.Enabled = true; _timer.Start(); } private async void Callback(object state, ElapsedEventArgs e) { // code await SomeAsyncFunc().ConfigureAwait(false); // code } } 

And one more question. Is deadlock possible in this code? Because it is used task. Result.

 List<Task> tasks = new List<Task>(); for(int i = 0; i < someLength; i++) { tasks.Add(SomeTaskFunc()); } await Task.WhenAll(tasks); for(int i = 0; i < tasks.Count; i++) { Task task = tasks[i]; // Дальше идут операции с task.Result } 
  • not "invalid in a GUI application" but in the UI layer. And where try..catch. In other places everywhere .ConfigureAwait (false) - vitidev

1 answer 1

Formally speaking, for a console application or service, the ubiquitous use of ConfigureAwait(false) really not necessary. Since the synchronization context is still missing, there is no need to bind a specific code to a specific context (as is the case with a UI application) - all code will work in the thread pool.

However, I would still recommend using ConfigureAwait(false) wherever possible, for two reasons:

  1. You will increase code reuse. If the code is then transferred to the GUI application, it will immediately work correctly.
  2. If you or the library you use need to set your context, your code will continue to work correctly (at least it will not change its behavior).

Answering specific questions:

  1. Not. As long as you do not have a synchronization context (or it is, but without a message loop) and you do not use blocking calls like Result and Wait() , you can forget about deadlocks.
  2. Will not be.
  3. I do not see the connection (a link to the article would help clarify the issue).

As for the async void methods, their main danger lies in two things that are not related to ConfigureAwait(false) :

  1. Exceptions that occur in such methods are not handled. For the timer and console application, this will mean the end of the process. Therefore, you must either look for fully asynchronous alternatives , or use a global try/catch callback.
  2. This method completes its execution, roughly speaking, immediately after the first await . Thus, if the asynchronous call itself or the code after the asynchronous call takes much time, the timer callback calls can overlap each other. You can bypass this by turning off the timer at the beginning of the method each time and turning it on again at the end of the method.

UPD

Is deadlock possible in this code? Because it is used task. Result.

The blocking wait for a task (via Result or Wait() ) does not in itself guarantee you a deadlock! Everything depends on the context and on what happens inside the called method. If there is nothing criminal inside SomeTaskFunc() , then deadlock is impossible, if only because by the time the Result call, all tasks have already completed their work ( await Task.WhenAll(tasks) ). And also because you have a console application and you use the same context. About blocking wait and read on this issue .

PS

It is written that using ConfigureAwait(false) not allowed in a GUI application, because it requires the original context after the asynchronous function

Not quite a valid statement. Use ConfigureAwait(false) in GUI applications is necessary wherever there is no need to continue in the UI stream. Those. omit ConfigureAwait(false) needed only in the UI code. Anywhere further along the call tree, the presence of ConfigureAwait(false) highly desirable (read, mandatory).

  • Also added a question in the description. Can you answer it yet? - Dima Gvozdev pm
  • @DimaGvozdev updated the answer. - andreycha