2015-04-16 6 views
1

Я понимаю, что мы должны избегать асинхронной синхронизации и наоборот. Вот два сообщения от Stephen Toub, объясняющие это красиво:Асинхронная синхронизация по сети с общим интерфейсом

Мы используем 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)); 
} 

ответ

1

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

Из этого сообщения об ошибке я нашел лучшее решение здесь: https://stackoverflow.com/a/28635558/177333. У вас есть синхронный интерфейс для реализации на стороне сервера и создания производного интерфейса, который добавляет async для клиентской стороны. Поскольку WCF игнорирует Async в имени при отправке сообщения по сети, вы вызываете один и тот же метод в любом случае.

2

Task.FromResult() не следует создавать дополнительные потоки или внести существенные накладные расходы. Это похоже на разумное исключение ?

Нет, это не разумное исключение (если у вас есть выбор), так как это вредит масштабируемости вашей службы WCF. В ваших интересах использовать естественно асинхронные API-серверы, если они доступны.

Что касается клиента, не имеет значения, определяет ли ваш метод интерфейса контракта WCF как PersonResult GetPerson(int id) или Task<PersonResult> GetPersonAsync(int id). Клиент будет работать в любом случае, даже без перекомпиляции прокси-сервера WCF. Для получения дополнительной информации:

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

+0

Действительно ли 'Task.FromResult()' действительно повреждает масштабируемость, если служба была синхронной для начала? Я понимаю, что async или нет не влияет на сообщение (в случае HTTP-привязки WSDL идентичен), но мы использовали один и тот же файл контракта с обеих сторон, и если сервер был синхронным, клиент не мог быть асинхронным. Из моего ответа видно, что это зависит от одной операции в обоих файлах контрактов, поэтому вы теряете часть автоматической проверки времени компиляции. Вероятно, я могу написать тесты, чтобы хотя бы убедиться, что они совпадают во время непрерывной интеграции. –

+0

'Task.FromResult' сам по себе не повреждает масштабируемость, метод синхронных сервисов, который он обертывает. Если такой метод не связан исключительно с ЦП, он, скорее всего, блокирует поток на стороне сервера, вызывая синхронный API ввода-вывода. Если вы не можете переписать его для использования API асинхронного ввода-вывода, нет смысла возвращать «Задачу». – Noseratio

+0

*, но мы использовали один и тот же файл контракта с обеих сторон, и если сервер был синхронным, клиент не мог быть асинхронным * - ** почему бы и нет? клиент все еще может быть асинхронным **. Вы определяете свой контрактный метод как «PersonResult GetPerson (int id)» в службе WCF и проверяете «генерировать операции на основе задач» при обращении к службе в клиентском приложении. 'Task GetPersonAsync (int id)' будет создан для вас. Тот факт, что он асинхронен на клиенте, не имеет ничего общего с тем, что он синхронный на сервере. – Noseratio

Смежные вопросы