Я понимаю, что мы должны избегать асинхронной синхронизации и наоборот. Вот два сообщения от Stephen Toub, объясняющие это красиво:Асинхронная синхронизация по сети с общим интерфейсом
- Should I expose asynchronous wrappers for synchronous methods?
- Should I expose synchronous wrappers for asynchronous methods?
Мы используем WCF для общения между уровнями и имеют общий контракт, используемый как сервисом и клиентом. Для создания прокси и канала клиент использует ChannelFactory<TContract>
. Одно из преимуществ этого заключается в том, что нам не нужно вручную обновлять наши [многие] ссылки на службы, и мы получаем автоматическую проверку времени компиляции с обеих сторон, если интерфейс изменился. Однако это также означает, что мы не можем поддерживать синхронный интерфейс на стороне сервера (не возвращая Task<Result>
), а также иметь асинхронный клиентский прокси (возврат Task<Result>
из-за сетевого хопа).
Так что мой вопрос в том, есть ли какой-либо реальный вред/недостаток, чтобы иметь контрактный тип возврата Task<Result>
, а на серверной стороне просто сделать return Task.FromResult(SyncCode());
? Мы эффективно выполняем асинхронную синхронизацию на стороне сервера, чтобы включить async на стороне клиента, но в любом случае сеть технически уже асинхронна. Task.FromResult()
не должен создавать никаких дополнительных потоков или вводить существенные накладные расходы. Это похоже на разумное исключение из правила?
Другими словами, я, возможно, реализацию, подобный следующему:
public PersonResult GetPerson(int id)
{
return SyncCode();
}
public Task<PersonResult> GetPersonAsync(int id)
{
return Task.FromResult(GetPerson(id));
}
Действительно ли 'Task.FromResult()' действительно повреждает масштабируемость, если служба была синхронной для начала? Я понимаю, что async или нет не влияет на сообщение (в случае HTTP-привязки WSDL идентичен), но мы использовали один и тот же файл контракта с обеих сторон, и если сервер был синхронным, клиент не мог быть асинхронным. Из моего ответа видно, что это зависит от одной операции в обоих файлах контрактов, поэтому вы теряете часть автоматической проверки времени компиляции. Вероятно, я могу написать тесты, чтобы хотя бы убедиться, что они совпадают во время непрерывной интеграции. –
'Task.FromResult' сам по себе не повреждает масштабируемость, метод синхронных сервисов, который он обертывает. Если такой метод не связан исключительно с ЦП, он, скорее всего, блокирует поток на стороне сервера, вызывая синхронный API ввода-вывода. Если вы не можете переписать его для использования API асинхронного ввода-вывода, нет смысла возвращать «Задачу». – Noseratio
*, но мы использовали один и тот же файл контракта с обеих сторон, и если сервер был синхронным, клиент не мог быть асинхронным * - ** почему бы и нет? клиент все еще может быть асинхронным **. Вы определяете свой контрактный метод как «PersonResult GetPerson (int id)» в службе WCF и проверяете «генерировать операции на основе задач» при обращении к службе в клиентском приложении. 'Task GetPersonAsync (int id)' будет создан для вас. Тот факт, что он асинхронен на клиенте, не имеет ничего общего с тем, что он синхронный на сервере. –
Noseratio