Как вызвать функцию asyn c, синхронизированную без блокировки основного потока? - PullRequest
3 голосов
/ 18 февраля 2020

Я написал простое консольное приложение для проверки ConfigureAwait (false) для решения проблемы вызова асинхронной функции c синхронизированным способом. Вот как я имитирую событие и пытаюсь вызвать асин c -функцию syn c.

 public static class Test2
    {
        private static EventHandler<int> _somethingEvent;

        public static void Run()
        {
            _somethingEvent += OnSomething;
            _somethingEvent(null, 10);
            Console.WriteLine("fetch some other resources");
            Console.ReadLine();
        }

        private static void OnSomething(object sender, int e)
        {
            Console.WriteLine($"passed value : {e}");
            FakeAsync().Wait();
        }

        private static async Task FakeAsync()
        {
            await Task.Delay(2000).ConfigureAwait(false);
            Console.WriteLine($"task completed");
        }
    }

вывод кода выглядит следующим образом:

passed value : 10
task completed
fetch some other resources

И когда я меняю функцию OnSomething на asyn c void, как это:

private static async void OnSomething(object sender, int e)
{
    Console.WriteLine($"passed value : {e}");
    await FakeAsync();
}

Вывод изменится на следующее:

passed value : 10
fetch some other resources
task completed

Вы можете увидеть получить некоторые другие ресурсы происходит до того, как задача выполнена раздел и это мой желаемый результат.
Мой вопрос заключается в том, как я могу добиться того же результата, вызвав функцию asyn c, синхронизированную как первая подпись, которую я написал для функции OnSomething ?
Как можно Я использую ConfigureAwait (false) , чтобы помочь мне в этой ситуации? Или, может быть, я не правильно его использую.

Ответы [ 2 ]

3 голосов
/ 18 февраля 2020

Я написал простое консольное приложение для проверки ConfigureAwait (false) для решения проблемы вызова асинхронной функции c синхронизированным способом.

Есть пара проблем с this.

  1. ConfigureAwait(false) не является «исправлением» для «проблемы» синхронного вызова асинхронной функции. Это один из возможных хаков , который работает в некоторых ситуациях, но, как правило, не рекомендуется, потому что вы должны использовать ConfigureAwait(false) везде во всем транзитивном закрытии этой функции, включая вторую и сторонние звонки - и если вы просто пропустите one , существует вероятность тупика. лучшее решение проблемы вызова асинхронной функции из синхронной функции заключается в изменении вызывающей функции на асинхронную (go "asyn c полностью") , Иногда это невозможно, и вам нужен хак , но в каждом сценарии нет хака, который бы работал.
  2. Проблема тупика , которую вы пытаетесь избежать имеет два компонента: блокирование потока задачи и однопоточный контекст. Консольные приложения не имеют однопоточного контекста , поэтому в консольном приложении весь ваш код использует ConfigureAwait(false) везде.

Вопрос в том, как можно ли добиться того же результата, вызвав синхронизированную функцию asyn c, как и первую подпись, которую я написал для функции OnSomething?

Код вызова будет блокировать асинхронный код (например, * 1036). *) или не будет (например, await). Вы не можете заблокировать асинхронный код и продолжить выполнение. Вызывающий поток должен либо продолжить выполнение, либо заблокировать; это не может сделать оба.

1 голос
/ 18 февраля 2020

Это потому, что когда вы звоните _somethingEvent(null, 10);, OnSomething не ожидается, поэтому следующее Console.WriteLine("fetch some other resources"); будет разрешено запускать сразу после выполнения await FakeAsync();.

Если вы не Перед продолжением нужно дождаться завершения OnSomething, просто сделайте пожар и забудьте:

private static void OnSomething(object sender, int e)
{
    Console.WriteLine($"passed value : {e}");
    Task.Run(() => FakeAsync());
}
...