Синхронный метод через асинхронный

110
20 августа 2019, 23:10

Многие API предоставляют как синхронные, так и асинхронные методы.

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

Ведь по сути в 99% логика не должна менять=> в синхронном методе вызываем асинхронную версию и ждем результата.

Answer 1

Это анти-паттерн. Если вы делаете библиотеку, синхронные методы должны быть строго синхронными, а асинхронные должны быть строго асинхронными.

Если разработчик вызывает синхронный метод, он ожидает, что выполнение не будет занимать потоки в тред-пуле (если суть метода не отображает явной необходимости такого поведения). Если вы сделали синхронный враппер, внутренние таски могут занимать потоки в тред пуле, и пользователь библиотеки может очень долго ловить ошибку. Кроме этого во время отладки намного удобней видеть синхронный call stack, нежели асинхронный.

Еще одна проблема. Например ваш класс/метод принимает как аргумент любую реализацию Stream, и разработчик ожидает, что синхронная версия метода будет вызывать синхронные методы на экземпляре Stream: Read/Write/Flush, а асинхронная будет работать с ReadAsync/WriteAsync/FlushAsync. Это логичное поведение, и не всегда пользователям библиотеки будут нужны дополнительные расходы на создания объектов Task, если они пользуются только MemoryStream.

При таком подходе будет дублироваться код, но с этим ничего не сделать.

Подробнее об этом: https://blogs.msdn.microsoft.com/pfxteam/2012/04/13/should-i-expose-synchronous-wrappers-for-asynchronous-methods/ В статье так же отмечено, что изначально метод HttpWebRequest.GetResponse работал через асинхронные методы, но потом это исправили, так как создавались некоторые проблемы.

Схожий вопрос на англоязычным stackoverflow: https://stackoverflow.com/questions/54261169/async-and-sync-versions-of-method

Пример оттуда же для уменьшения дублирования кода:

private static async Task DownloadToCacheAsync(bool sync)
{
  ...do some analysis to get download locations...
  using (var wc = new WebClient())
  {
    if (sync)
      wc.DownloadFile(new Uri(content.Url), targetPath);
    else
      await wc.DownloadFileTaskAsync(new Uri(content.Url), targetPath);
  }
  ...do other stuff...
}
public static Task DownloadToCacheAsync() => DownloadToTaskAsync(sync: false);
public static void DownloadToCache() => DownloadToTaskAsync(sync: true).GetAwaiter().GetResult();
READ ALSO
Как реализовать таймаут на C#?

Как реализовать таймаут на C#?

Доброго времени суток всем читающим!

104
Не работает сравнение объектов по полям C#

Не работает сравнение объектов по полям C#

Есть вот такой код для сравнения двух объектовПроблема в том, что if() с проверками на тип, имя и значение полей работает как-то неадекватно

89
Правильно ли я сделал таймер?

Правильно ли я сделал таймер?

Часы, минуты и секунды задаю с инспектораМне не нужен сверхточный таймер, но принцип правильный? А может есть какие-нибудь более легкие способы,...

95
Персонаж должен тащить обьект [закрыт]

Персонаж должен тащить обьект [закрыт]

подскажите как это реализовать:Персонаж должен тащить объектВ инете искал ничего не нашел

94