Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > C/C++: Общие вопросы > Зачем нужна Boost.Coroutine |
Автор: bsa 5.1.2013, 13:11 |
В http://www.boost.org/doc/libs/1_53_0_beta1/ будет включена библиотека coroutine. Прочитав описания стало понятно, как ее использовать, и как она работает. Но для меня пока остается загадкой ответ на вопрос: А ЗАЧЕМ? Единственное, что я могу предположить - деление больших неделимых операций на несколько маленьких. И это все? Может еще зачем-то она нужна и мне это позарез необходимо, но я не понимаю? Одно точно я вижу, структура программы, использующей ее, значительно усложнится. И без внятной документации понять принцип работы программы будет ой как затруднительно. Подобное происходит, например, с asio. Но там хоть понятно - поставил задачу, до нее дошла очередь, она выполнилась. А тут? Работаешь, сохранил контекст, прыгнул (восстановил другой контекст) в середину другой функции, поработал, прыгнул в середину третьей... ![]() |
Автор: NoviceF 5.1.2013, 15:49 |
фанаты goto давно ждали возможности для реванша ![]() |
Автор: bsa 6.1.2013, 13:40 |
![]() Реванш слишком жестокий... Кстати, хочется услышать мнение boostcoder на этот счет - он сильно радовался этой либе. |
Автор: maxim1000 6.1.2013, 20:31 |
если не злоупотреблять, штука довольно полезная как минимум удобно при обработке последовательностей, при конвертации всяких данных, в некоторых алгоритмах (особенно тех, которые являются комбинацией нескольких сложных кусков) представим себе, что у нас есть последовательность 123456789101112131415... (цифры всех чисел записаны друг за другом), нужно посчитать сумму всех элементов на чётных местах до 1000-го. вывести символы последовательности одним циклом по номеру числа - проще простого, посчитать искомую сумму другим циклом по номеру символа - ещё проще проблемы: 1. предварительно считать может будть накладно по памяти 2. далеко не для всех алгоритмов можно заранее сказать, сколько понадобится элементов без запуска алгоритма самый простой выход - объединить два куска кода, т.е. вместо закидывания во временное хранилище мы просто отбрасываем нечётные, а чётные складываем проблемы: 1. для одного алгоритма естественен цикл по числам, для второго - по символам, что бы мы ни выбрали, код одного из них станет сложнее 2. переменые, отвечающие за состояния алгоритмов (аккумулятор, номер числа) доступны обоим алгоритмам 3. алгоритм генерации последовательности и вычисления искомого значения, по-хорошему, не должны знать ничего друг о друге, тогда легче станет менять последовательности и вычисления независимо 4. плохо масштабируется (ведь может быть целая цепочка преобразований последовательностей) следующий выход - сконвертировать один из алгоритмов во что-то вроде функтора и дёргать его из другого, пример (не для вышеописанной задачи) - std::istream_iterator и какой-нибудь алгоритм из namespace std, можно даже и то, и то, оставив главный цикл одиноким в своей функции (std::istream_iterator, std::find_if, функтор для отсева) в принципе, этот вариант решает все проблемы, но получается довольно-таки неудобным, например , генерировать последовательность, описанную в начале, по одному символу неудобно - нужно больше переменных состояния, код сложнее, да и производительность похуже, с вычислением суммы тоже нужна дополнительная переменная появляется а в случае с coroutines что построение последовательности, что вычисление искомой суммы представляются обычными циклами, циклы эти находятся в разных функциях, друг о друге почти ничего не знают, переменные состояния скрыты, всё хорошо P.S. с Boost.Coroutines я не работал, подробностей не знаю, описывал общее понятие coroutines |
Автор: EvilsInterrupt 6.1.2013, 23:54 |
maxim1000, Если не сложно, то можно еще один пример где пригодится эта новая фича? Я привык понимать на нескольких. |
Автор: boostcoder 7.1.2013, 14:04 |
я дал слово, не использовать этот форум по назначению. так, некоторые свои темы буду обновлять. зы на самом деле, в связи с беспределом администрации сего ресурса(от чем я неоднократно писал http://forum.vingrad.ru/forum/forum-316.html), мне множество раз предлагали сменить ресурс, многие из тех кто еще недавно пользовался этим форумом и перестали. |
Автор: NoviceF 7.1.2013, 14:34 |
![]() |
Автор: Pfailed 7.1.2013, 14:58 |
Сопрограммы можно эффективно использовать в сетевом программировании. Предположим в одной функции вы произвели неблокирующий connect, следующая операция в этой функции -- запись в приконнекченный сокет. Естественно пока сокет не законнектится записывать бессмысленно, соответственно имеет смысл на это время переключиться в другую функцию и выполнить другое полезное действие. Таким образом получаем эффективное приложение и все в рамках одного процесса и потока. |
Автор: EvilsInterrupt 7.1.2013, 15:51 | ||
Очень похоже на yeld в генераторах Python и др. современных скриптовых языках. |
Автор: baldina 7.1.2013, 23:07 | ||||||||||||||
с точностью до наоборот. вы слишком вникаете в технику исполнения, а следует думать концептуально. технически: сопрограмма имеет состояние, в которое возвращается при каждом последующем вызове. вызов завершается "оператором" возврата yield да. можно сказать, что сопрограммы реализуют yield, а остальное вытекает из этого факта. точно также можно сказать, что сопрограммы имеют состояние и множество точек входа, из которых конкретная определяется состоянием. из этого вытекает возможность реализации yield. сопрограммы - всего лишь инструмент, без него можно жить, но есть ситуации, когда использование сопрограмм дает более короткие и ясные программы. обычно выделяют три ситуации: 1. конечные автоматы. здесь польза прямо вытекает из определения: сопрограмма меняет состояния автоматически, без привлечения специальных механизмов. пример: для реализации автомата, который безусловно переходит в состояния 1->2->3 достаточно написать функцию-сопрограмму
в boost::coroutine все не так лаконично
но идея ясна; это значительно экономичнее и прозрачнее конструкции
а если надо иметь несколько контекстов, вместо static int state потребуется целый огород. 2. генераторы. функции, генерирующие последовательность. возвращаемое значение можно интерпретировать как итератор.
в boost::coroutine и с итераторами:
немного похоже на fsm, правда? действително, fsm - обобщение генераторов в С++ без сопрограмм в простейшем случае нужно поддерживать контейнер для исходящих значений либо лишние параметры, в более сложном - слишкоммногабукф 3. модель взаимодействия акторов (actors). похоже на взаимодействие объектов в ООП (посылкой сообщений\вызовом методов), но отличается независимостью взаимодействующих единиц (вплоть до их параллельного исполнения). это модель типа источник/приемник (producer/consumer), ближайшая аналогия - межсетевое взаимодействие (по протоколу). т.к. акторы (actors) являются сопрограммами, каждая может "думать" в удобных ей единицах: пакетах, запросах и т.п.. это как раз тот пример, который привел maxim1000. более классический пример - взаимодействие лексического и синтаксического анализатора: каждый является функцией, они исполняются параллельно, но у каждого свои "вехи": лексическому анализатору удобно мыслить в терминах лексем, синтаксическому - в терминах конструкций. |
Автор: volatile 8.1.2013, 00:07 | ||||
baldina, все замечательно, только ваши примеры делают не то что написано, если я не ошибаюсь конечно. Это же не генератор факториалов, а генератор квадратов, или что-то типа того...
И это тоже не генератор факториалов. ген. факториалов будет как-то так:
Извините что вмешиваюсь, но примеры сбивают с толку просто. |
Автор: bsa 8.1.2013, 00:09 |
Исправь, это же типичное UB. В целом, я пока не проникся... Что-то гложат меня сомнения об эффективности смены контекста (значений всех регистров) по сравнению с вызовом функции (которая может быть встроена, если компилятор это посчитает разумным). Работа с потоками уже, вроде, решена в ASIO. По сути, там тоже самое, только через вызовы функций. Хотя, может в случае парсеров все несколько иначе - я ими не особо занимался. Проблема генераторов решается путем выноса их контекста за пределы функций (типичный класс), причем, это будет эффективнее сопрограмм - нет восстановлений регистров процессора. Я неправ? |
Автор: baldina 8.1.2013, 00:38 | ||
да. был пьян, поторопился))) ну, суть ясна, я думаю Добавлено через 13 минут и 51 секунду bsa, все это так.
еще раз повторю: дело не в низкоуровневой реализации, а в высокоуровневной интерпретации, в подходе. это парадигма. ясно, что контекст можно обернуть в класс, можно передать в качестве параметра. вопрос не в том, как реализовать фичу, а как реализовать удобным образом. как я понимаю, yield это часть концепции функционального подхода (и хотя в явном виде далеко не во всех функциональных языках присутствует, три описанные ситуации так или иначе в функциональных языках обычно реализуемы). сопрограммы естественно реализуемы на ассемблере (как это описано у Кнута), а в языках, где есть лишь подпрограммы, реализация требует известных ухищрений. можно использовать или не использовать ООП, обобщенное программирование. можно обойтись без мультиметодов, сравнения с образцом, делегатов и лямбда-функций и т.д. Однако имея эти средства, можно что-то делать яснее и короче. Только и всего. с точки зрения реализации самый простой пример преимущества сопрограмм - возможность отказа от switch в тех ситуациях, когда его нельзя заменить на полиморфизм. |
Автор: baldina 8.1.2013, 01:04 | ||
м-да, с примерами не очень. исправил ![]() Добавлено через 7 минут и 32 секунды
bsa, мне даже неловко вам говорить о преждевременной оптимизации... но вообще говоря, любое высокоуровневое решение может повлечь дополнительные накладные расходы. при этом (часто незначительный, по сути) проигрыш в производительности компенсируется выигрышем в затратах на разработку и сопровождение. в примерах Кнута (на MIXе) накладных расходов нет вообще: сопрограмма отличается от подпрограммы лишь тем, что адрес возврата, помещаемый в стек, всегда разный. |
Автор: bsa 8.1.2013, 09:53 | ||
честно говоря, пока я не прочитал еще раз документацию, я не мог понять, как работает генератор из твоего примера. Не уверен, что эта фича упростит понимание программы. Чтобы ее понимать, нужно знать о ней. |
Автор: baldina 8.1.2013, 15:14 |
![]() что такое массив и список, чем они похожи и отличаются, где они хороши и плохи и т.д. должен знать каждый. так? что такое подпрограммы - тем более. про сопрограммы - из того же разряда. если бы вопрос крутился не вокруг библиотеки С++, а вокруг языка, непосредственно поддерживающего сопрограммы, вопроса скорее всего просто не возникло бы. bsa, пока не прочитать про ООП, программисту С непонятно что такое класс, как оно работает и т.п. тут то же самое. я отнюдь не хвалю boost::coroutine и не агитирую за испольование сопрограмм. да и примеры, согласен, лучше специально подготовленные, а не на коленке. но тогда уж надо открывать учебники и читать про концепции, преимущества и пр. в книгах это всегда полнее, чем любой ответ на форуме. |
Автор: bsa 8.1.2013, 17:42 |
baldina, думаю ты согласишься с утверждением, что хороший язык программирования отличается от плохого помимо всего прочего ясностью кода. Действия break, return, continue, do, while, if, else и goto вполне очевидны. А вот yield... Ну ладно. Я понял, что существуют задачи, где использование сопрограмм имеет смысл. Другое дело, что я таких не припомню. |
Автор: volatile 8.1.2013, 18:38 |
baldina, Еще раз извиняюсь за занудство, исправьте уж нормально, а то теперь у вас генератор нулей получился. bsa, ну это как рекурсия. любую задачу можно решить без нее, согласитесь. Но встречаются задачи (изредка) которые с рекурсией получаются гораздо короче и понятней. С этим точно также. |
Автор: bsa 8.1.2013, 19:40 |
volatile, я не спорю. |
Автор: chaos 7.3.2013, 13:49 |
Чото нифига пока понять не могу. Вопрос по первому же рисунку из доки ![]() Что нужно написать в main что бы получить такой же оутпут? |
Автор: bsa 7.3.2013, 18:15 |
Там речь идет о том, как такое сделать. |
Автор: EvilsInterrupt 31.3.2013, 12:18 |
Может кому-то пригодится. Для чего и зачем применять сопрограммы(coroutine). На мой взгляд достаточно лаконично и понятно описано в справочнике по Python Девид Бизли 4. изд. 2010 г. Пояснения : стр.136 - Замыкания, декораторы, генераторы, сопрограммы Примеры использования: стр.146(генераторами), стр.42, стр.147 (сопрограммы) |