освободить вызывающий поток при вызове функции asyn c в синхронном контексте - PullRequest
0 голосов
/ 16 июня 2020

Кажется, что в c# (do tnet core 3.1) невозможно вызвать асинхронную функцию из неасинхронного c метода без блокировки исходного потока. Почему?

Пример кода:

public async Task myMethodAsync() {
  await Task.Delay(5000);
}

public void callingMethhod() {
  myMethodAsync().Wait(); // all flavours of this expression, like f.ex. .Result seem to be blocking the calling thread
}

Какое техническое ограничение дает возможность освободить вызывающий поток до тех пор, пока метод asyn c не завершится, а затем продолжить выполнение оттуда? Это что-то технически невозможное?

Ответы [ 2 ]

4 голосов
/ 16 июня 2020

Да, это ожидаемо. Это почему существует концепция Task и c. Если бы можно было делать то, что вы хотите: , им не нужно было бы - мы могли бы просто взмахнуть палочкой, и все было бы асинхронно c. Вся суть ожидаемых типов заключается в том, что освобождение вызывающего потока при разрешении последующего продолжения является жестким и требует координации и участия вызывающего кода; и от того, что это когда-либо называется; et c - полностью вверх по стеку до того, что запускает потоки. Ваш код callingMethhod синхронный: он может делать только несколько вещей:

  • он может работать до завершения - это означает: ему придется заблокировать
  • , он может бросить исключение

В результате этого async / await является заразным; все, что касается ожидаемых вроде как, должно также быть ожидаемым , что означает: вы обычно вызываете myMethodAsync только из callingMethhod, который вернул [Value]Task[<T>], и который предположительно async с await (хотя в показанном примере эти биты не являются обязательными).

3 голосов
/ 16 июня 2020

Кажется, что в c# (do tnet core 3.1) невозможно вызвать асинхронную функцию из неасинхронного c метода без блокировки исходного потока. Почему?

Потому что синхронный означает . Синхронный означает, что он блокирует поток до тех пор, пока метод не будет завершен.

Какое техническое ограничение дает возможность освободить вызывающий поток до завершения метода asyn c, а затем продолжить выполнение оттуда? Это что-то технически невозможное?

Если ваш вызывающий метод хочет освободить свой поток, сделайте его асинхронным. Асинхронные методы могут освобождать вызывающие их потоки. Здесь нет ничего невозможного; это было решено с помощью async и await.

Теперь, если вы спрашиваете, «почему каждый метод не может неявно быть async», то это теоретически возможно, но вызывает пара основных вопросов. Это невозможно сделать в C# по причинам обратной совместимости. Сразу приходят в голову две проблемы:

  1. Ограниченное взаимодействие. Невозможно использовать язык «все есть async» для взаимодействия с чем-либо, что использует многопоточность старой школы (мьютексы Win32 и др.).
  2. Неожиданный параллелизм. Существует партия сценария ios, где разработчики предполагают синхронный код. Если каждый метод потенциально асинхронен, то даже такой простой код, как var x = this._list[0]; this._list.RemoveAt(0);, больше не безопасен.
...