Ви поставили кілька запитань у своєму запитанні. Я розбию їх трохи інакше, ніж ви. Але спершу дозвольте безпосередньо відповісти на питання.
Ми всі хочемо, щоб камера була легкою, якісною та дешевою, але, як говориться, з цих трьох ви можете отримати лише максимум дві. Ви знаходитесь тут у тій самій ситуації. Вам потрібно рішення, яке є ефективним, безпечним і ділить кодом між синхронним та асинхронним шляхами. Ви збираєтесь отримати лише два таких.
Дозвольте мені зламати, чому це так. Почнемо з цього питання:
Я бачив, що люди кажуть, що ви можете використовувати GetAwaiter().GetResult()
метод асинхронізації та викликати його зі свого методу синхронізації? Чи безпечна ця нитка у всіх сценаріях?
Суть цього питання полягає в тому, "чи можу я поділити синхронний та асинхронний контури, зробивши синхронний шлях просто зробити синхронним очікування на асинхронній версії?"
Дозвольте мені бути зрозумілим щодо цього, оскільки це важливо:
ВИ МОЖЕТЕ НЕБЕЗПЕЧНО ЗАСТОСУВАТИ ВСІ РОБОТИ ВІД СУМОВІВ ЦІХ ЛЮДЕЙ .
Це вкрай погана порада. Синхронно отримати результат від асинхронного завдання дуже небезпечно, якщо у вас немає доказів того, що завдання виконано нормально або ненормально .
Причина цього надзвичайно погана порада - ну, врахуйте цей сценарій. Ви хочете скосити газон, але ваше лезо газонокосарки зламане. Ви вирішили дотримуватися цього робочого процесу:
- Замовте нове лезо з веб-сайту. Це асинхронна операція з високою затримкою.
- Синхронно чекати - тобто спати, поки у вас не буде лезо в руці .
- Періодично перевіряйте поштову скриньку, щоб побачити, чи прибув лезо.
- Вийміть лезо з коробки. Тепер у вас це є в руці.
- Встановіть лезо в косарку.
- Косити газон.
Що сталося? Ви вічно спите, тому що операція перевірки пошти тепер відстежується тим, що відбувається після надходження пошти .
Це дуже легко потрапити в таку ситуацію , коли ви синхронно чекати довільної задачі. Це завдання може мати заплановану роботу в майбутньому потоці, який зараз чекає , і тепер це майбутнє ніколи не надійде, тому що ви його чекаєте.
Якщо ви робите асинхронне зачекання, тоді все добре! Ви періодично перевіряєте пошту, і поки ви чекаєте, ви робите бутерброд або робите податки чи що завгодно; ви продовжуєте виконувати роботу, поки ви чекаєте.
Ніколи не чекайте синхронно. Якщо завдання виконано, воно зайве . Якщо завдання не виконано, але заплановане пробіг поточного потоку, воно малоефективне, оскільки поточний потік може обслуговувати іншу роботу замість очікування. Якщо завдання не виконано і графік запуску поточного потоку, він висить, щоб синхронно чекати. Немає вагомих причин знову синхронно чекати, якщо ви вже не знаєте, що завдання виконане .
Для подальшого читання з цієї теми див
https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
Стівен пояснює сценарій у реальному світі набагато краще, ніж я можу.
Тепер розглянемо "інший напрямок". Чи можемо ми поділитися кодом, зробивши асинхронну версію просто зробити синхронну версію на робочій нитці?
Це, можливо, і, мабуть, погана ідея з наступних причин.
Це неефективно, якщо синхронна операція є роботою вводу з високою затримкою. Це по суті наймає працівника і змушує цього працівника спати, поки не буде виконано завдання. Нитки шалено дорогі . Вони за замовчуванням споживають мільйон байт адресного простору, вони забирають час, беруть ресурси операційної системи; ви не хочете спалювати нитку, виконуючи марну роботу.
Синхронна операція може бути записана не як безпечна для потоків.
Це є більш розумним , якщо метод високу латентність роботи процесора пов'язані, але якщо це , то ви , ймовірно , не хочете , щоб просто передати його в робочий потік. Ви, ймовірно, хочете використовувати паралельну бібліотеку завдань, щоб паралелізувати її якомога більше процесорів, ви, швидше за все, хочете скасувати логіку скасування, і ви не можете просто змусити синхронну версію робити все це, оскільки тоді це вже буде асинхронна версія .
Подальше читання; знову ж таки, Стівен пояснює це дуже чітко:
Чому б не використовувати Task.Run:
https://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-using.html
Більше сценаріїв "робити і не робити" для Task.Run:
https://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-dont-use.html
Що це тоді залишає нас? Обидві методи обміну кодом призводять або до тупикових ситуацій, або до великих неефективностей. Висновок, до якого ми дійшли, - це ви повинні зробити вибір. Ви хочете, щоб програма була ефективною та правильною та радує абонента, чи ви хочете зберегти кілька натискань клавіш, спричинених шляхом дублювання невеликої кількості коду між синхронним та асинхронним шляхами? Боюсь, ви не отримаєте обох.