Исправление : как следует из двух ответов, проблема, похоже, специфична для dart , поскольку C # реализует Task.Wait, позволяя достичь желаемого эффекта. Я был бы признателен за любую дополнительную информацию о причинах, по которым это невозможно в дротике, или о том, как этого добиться там. Буду рад закрыть вопрос в его нынешнем виде.


Бывают ситуации, когда имеет смысл заставить синхронные функции использовать асинхронные вызовы внутренне, ожидая их завершения, прежде чем доставить результат. Это явно не разрешено как в C # , так и в Dart : все, что использует await, должно быть помечено как async (таким образом, возвращается будущее).

Простой пример в Dart , но то же самое справедливо для C # :

Отказ от ответственности: я бы поступил иначе, поэтому не предлагайте «правильное» решение преобразования всех методов в асинхронные ; код здесь просто для иллюстрации вопроса.

У меня есть полностью асинхронная реализация общей оболочки для HTTP-запросов к некоторому конкретному REST API. Он выполняет вход в систему, аутентификацию и т. Д .:

class RequestProcessor {
     Future post(String path, [payload]) async {
          return request("POST", path, payload);
     }
}

Я хотел бы реализовать высокоуровневый пользовательский API, переводящий запросы к REST-API. Некоторые из этих методов я хотел бы иметь синхронными. Вот что я хотел бы и не имею права иметь:

class API {
    final RequestProcessor processor;

    API(this.processor);

    // this takes long and should be asynchronous, happy with a future (OK)
    Future getQueryResults(query) async {
        return await processor.post("/query", query);
    }

    // here I would prefer to have it synchronous (COMPILE ERROR)
    String getVersion() {
        return await processor.post("/version");
    }
}

Вопрос: Почему это запрещено?

0
Oleg Sklyar 26 Окт 2015 в 13:52

4 ответа

Лучший ответ

await - это асинхронное ожидание, поэтому не имеет смысла использовать его в синхронной функции. Чтобы быть асинхронным, метод должен возвращаться при инициировании ожидаемой операции, тогда как синхронный метод должен выполняться до завершения.

Вместо этого вы можете использовать синхронное ожидание, и в этом случае ваш метод не обязательно должен быть async. В C # это можно сделать, вызвав метод Wait() для возвращенной задачи.

3
Ned Stoyanov 26 Окт 2015 в 11:05

В Dart маркировка функции / метода async сообщает виртуальной машине, что ей необходимо переписать код перед его выполнением. await не изменяет асинхронную функцию на синхронизирующую, функция остается асинхронной, она просто допускает более удобный синтаксис, чем цепочки then(() { return ...then(() { return...})}).

Если вы выполняете асинхронный вызов, все последующее является асинхронным, вы ничего не можете с этим поделать.

0
Günter Zöchbauer 26 Окт 2015 в 11:54

Потому что ожидание и возвращение в будущее принципиально разные.

Возврат будущего освобождает текущий поток и при необходимости планирует продолжение на более позднее время, ожидание блокирует текущий поток.

Например, в потоке пользовательского интерфейса возврат будущего - это нормально, но ожидание приведет к зависанию пользовательского интерфейса, в потоке веб-сервера ожидание заблокирует поток и не позволит веб-серверу обрабатывать дополнительные запросы и т. Д.

Возможно даже ожидание того, что должно быть асинхронной операцией, вызовет тупик.

.net предоставляет Task.Wait, когда вы знаете, что с ожиданием все в порядке, я не знаю о dart, но это не происходит автоматически (за исключением предложений await внутри catch в методах async в C #)

2
Nir 26 Окт 2015 в 11:03

Это выбор дизайна. Dart является однопоточным - каждый вызов синхронной функции будет выполняться до завершения, прежде чем разрешить выполнение любого другого кода. Если вы разрешите синхронной функции блокироваться, пока не будет завершено будущее, тогда никакой другой код не будет выполняться, и будущее никогда не будет завершено (потому что код, который его завершил, не может работать).

Возможна система, которая позволяет запускать другой код, в то время как одна синхронная функция заблокирована. Для этого требуется либо наличие более одного активного стека (параллельного или нет), либо неявное преобразование всей программы в асинхронную. Когда вы компилируете в JavaScript, оба варианта плохи, поэтому Дарт не пытался этого сделать.

4
lrn 27 Окт 2015 в 13:46