Прежде чем я попытаюсь дать что-то, что напоминает ответ на ваш вопрос, я чувствую, что мне нужно, чтобы вы знали о важной проблеме, и это то, что в C # 7.1 или выше вы можете использовать асинхронный метод Main.Вы можете прочитать больше об этом в Что нового в C # 7.1 , но TL; DR, после переключения вашего проекта на C # 7.1 или выше, или "последней версии", вы можете сделать это:
public class Program
{
public static async Task Main(string[] args)
{
using(MyEntityService repo=new MyEntityService())
{
MyEntity myEntity=await repo.Get("foobar");
//do stuff
}
}
}
Теперь давайте попробуем ответить на ваш вопрос.Имейте в виду, что мои знания об асинхронности / ожидании могут быть ошибочными / неполными, поэтому могут появиться другие ответы, которые лучше справляются с этой задачей.
С этим из пути, что самое важное, асинхронность будетдобавить в свой код? Сложность .
Каждый раз, когда вы объявляете метод как async
, компиляция всего метода изменяется.Все это превращается в конечный автомат и переписывается и перемещается.Если впоследствии вы декомпилируете свою программу, если декомпилятор действительно продвинутого типа, декомпилированный код будет выглядеть не так, как ваша оригинальная программа.
Теперь этот конечный автомат добавит заметные накладные расходы к выполнению программы, с точки зрениявремя выполнения или использование памяти?Нет, не совсем.
Другой вопрос заключается в том, сколько издержек при использовании асинхронной версии по сравнению с неасинхронной версией может быть добавлено, и на это нет никакого способа ответить.Весь механизм и все различные варианты могут означать, что их много или их почти нет, это зависит от того, какой API вы используете, и что / как он делает.
Один изПроблемы, с которыми вам придется иметь дело, это когда речь идет об исключениях.Трассировка стека становится ... интересной ... когда вы задействуете методы, объявленные как async
.
Например, с учетом этой короткой программы (которую я запускал с использованием LINQPad ):
async Task Main()
{
await Test1();
}
public static async Task Test1()
{
await Task.Delay(1000);
throw new Exception("Test");
}
Можно ожидать, что трассировка стека исключительной ситуации будет содержать Main
, но, увы, из-за того, что оператор throw
выполняется после того, как задача «всплыла» после задержки, она будетвыполняется каким-то фреймворковым кодом, и трассировка стека на самом деле выглядит следующим образом:
at UserQuery.<Test1>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at UserQuery.<Main>d__0.MoveNext()
Я думаю, что вы действительно ищете некоторые рекомендации о том, как работать с асинхронным кодом, и лучшиймогут сделать следующее:
- Если вы пишете синхронный код и имеете дело с API, который имеет синхронные методы, используйте синхронные методы
- Если вы пишете асинхронный код,и для работы с API, который имеет асинхронные методы, используйте асинхронные методы
- Если вы пишете синхронный код, и для работы с API, который имеет асинхронные методы, используйтеасинхронные методы, используйте
.Wait()
или .Result
, чтобы получить результат и точно знать что вы делаете - Если вы пишете асинхронный код,и имея дело с API, который имеет синхронные методы, используйте асинхронные методы
(Имейте в виду, что я никоим образом не говорил о , что методыAPI делали;я предполагаю, что если API предоставляет асинхронные методы, то для этого есть причина)