Позвольте Эрику Липперту ответить на этот вопрос:
Очевидный вопрос на данный момент: если CPS такой классный, то почему бы нам не использовать его постоянно? Почему большинство профессиональных разработчиков никогда не слышали об этом, или те, кто имеет, думают об этом как о чем-то, что делают только эти сумасшедшие программисты на Scheme?
Во-первых, большинству людей, привыкших думать о подпрограммах, циклах, try-catch-finally и т. Д., Просто сложно рассуждать о том, как делегаты используются для управления потоком таким образом. Я сейчас просматриваю свои заметки о CPS из CS442 и вижу, что в 1995 году я записал профквот: «С продолжениями вы должны встать на голову и вытащить себя наизнанку». Профессор Дагган (*) был абсолютно прав, говоря это. Вспомните пару дней назад, что наш крошечный пример преобразования CPS выражения C # M (B ()? C (): D ()) включал четыре лямбды. Не все хорошо умеют читать код, который использует функции высшего порядка. Это накладывает большие когнитивные нагрузки.
Более того: одна из приятных особенностей встроенных в язык специальных операторов потока управления заключается в том, что они позволяют вашему коду четко выражать значение потока управления, скрывая при этом механизмы - стеки вызовов и адреса возврата, списки обработчиков исключений и защищенные области. и так далее. Продолжения делают механизмы управления потоком явными в структуре кода. Весь этот акцент на механизме может сокрушить смысл кода.
В следующей статье он объясняет, как асинхронность и продолжения в точности эквивалентны друг другу, и рассказывает о том, как выполнить простую (но блокирующую) синхронную сетевую операцию и переписать ее в асинхронном стиле, убедившись, что все скрытые есть ошибки, которые должны быть покрыты, чтобы понять это правильно. Это превращается в огромный беспорядок кода. Его резюме в конце:
Боже мой, какой ужасный беспорядок мы сделали. Мы расширили две строки совершенно чистого кода до двух десятков строк самых чудовищных спагетти, которые вы когда-либо видели. И, конечно, он все еще не компилируется, потому что метки не находятся в области видимости, и у нас есть определенная ошибка присваивания. Нам все еще нужно переписать код, чтобы исправить эти проблемы.
Помните, что я говорил о плюсах и минусах CPS?
- PRO: Произвольно сложные и интересные потоки управления могут быть построены из простых частей - проверьте.
- CON: Реализацию потока управления через продолжения трудно читать и трудно обдумать - проверить.
- CON: код, представляющий механизмы потока управления, полностью переопределяет смысл кода - проверка.
- CON: Преобразование обычного потока управления кодом в CPS - это то, с чем хорошо справляются компиляторы, и почти никто другой - проверка.
Это не какое-то интеллектуальное упражнение. Реальные люди заканчивают тем, что пишут код, морально эквивалентный вышеупомянутому, все время, когда они имеют дело с асинхронностью. И по иронии судьбы, даже несмотря на то, что процессоры стали быстрее и дешевле, мы проводим все больше и больше времени в ожидании того, что не связано с процессором. Во многих программах большая часть времени тратится на привязку процессора к нулю в ожидании сетевых пакетов, чтобы совершить поездку из Англии в Японию и обратно, или вращения дисков, или чего-то еще.
И я даже не говорил о том, что произойдет, если вы захотите составить асинхронные операции дальше. Предположим, вы хотите сделать ArchiveDocuments асинхронной операцией, которая принимает делегата. Теперь весь код, который его вызывает, также должен быть написан на CPS. Загрязнение просто распространяется.
Правильная асинхронная логика важна, она станет еще
более важной в будущем, а инструменты, которые мы вам дали, заставят вас
«стоять на голове и вывернуть себя наизнанку», как мудро сказал профессор Дагган.
Стиль передачи продолжения является мощным, да, но должен быть лучший способ эффективно использовать эту мощь, чем код выше.
Обе статьи и последующие серии, посвященные новой функции языка C #, которая переносит весь этот беспорядок в компилятор и позволяет писать ваш код как обычный поток управления со специальным ключевым словом, чтобы пометить определенные части как асинхронные, стоит прочитать, даже если вы не разработчик C #. Я нет, но это был по-прежнему весьма поучительный опыт, когда я впервые столкнулся с ним.