Как безопасно смешивать синхронизацию и асинхронный код?

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

Я изменил базовую реализацию на async и разоблачил методы async для тех, кто хочет ее использовать. Но теперь у меня много реплицированного кода. Кажется, что код Async работает лучше. Я бы хотел, чтобы существующие клиенты воспользовались этим, и я хочу исключить повторение кода.

Есть ли безопасный способ сохранить подпись синхронизации и выполнить асинхронную реализацию?

Я специально боюсь тупиков при вызове .Result и .Wait.

Ответ 1

Я сильно запрещаю вам не делать этого

Сначала прочитайте Должен ли я выставлять синхронные обертки для асинхронных методов? и Должен ли я открывать асинхронные обертки для синхронных методов? от Stephan Toub.

Основные причины, по которым я не буду этого делать:

  • Синхронизация по Async - как вы сказали, тупиковые ситуации. Выше или ниже по цепочке звонков, используя Result или Wait в async, возможно, рискованный бизнес. Это зависит от того, какую платформу вы выполняете (ASP.NET, UI, Console), поскольку каждый ведет себя по-другому (даже при использовании ConfigureAwait(false))

  • Async over Sync - масштабируемость. Как только я вижу конечную точку async, я предполагаю, что это чистый async, который для меня, поскольку потребитель API означает, что нет ни одной нити, вращающейся "за моей спиной". Если ваши пользователи предполагают то же самое, выясняя, что для каждого вызова метода асинхронизации используется поток потока нитей, который может повредить производительность при попытке масштабирования. Если пользователи хотят обернуть метод синхронизации с помощью Task.Run, оставить его для них, чтобы сделать этот вызов, и принять решение о том, как это повлияет на их приложение.

Ответ 2

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

Консольные приложения ведут себя не так, как от веб-приложений и приложений пользовательского интерфейса, насколько они справляются с блокировками, если они НЕ обрабатываются надлежащим образом. Если вы используете MVC, используйте асинхронную задачу ActionResult и оберните специальные синхронные вызовы в Task.Run(() = > SYNCCODE), используя async и ожидайте. Аналогичный процесс с UI-кодом, используя async/await при использовании методов событий (таких как обработчики событий Click).

Я обычно переношу свои вызовы синхронизации с асинхронными версиями и обрабатываю их как задачи. Если эти методы синхронизации могут использовать Async-версии .NET-методов, я стараюсь "глубже", когда это возможно.