Стековые/безстековые      сопрограммы и           Boost.Asio          Eugene Kulak           keu@cilkum.net      C++ Satur...
Сопрограммы
Сопрограммы„ Подпрограммы – это частные случаи более общих программныхкомпонентов, называемых сопрограммами. В противополо...
Сопрограммыподпрограмма               подпрограмма
Сопрограммыподпрограмма               подпрограмма
Сопрограммыподпрограмма               подпрограмма
Сопрограммысопрограмма              подпрограмма
Сопрограммысопрограмма              подпрограмма
Сопрограммысопрограмма              подпрограмма
СопрограммыСтэк       А       В       С
СопрограммыАВС
СопрограммыАВС
СопрограммыАВС
СопрограммыАВС
СопрограммыКлассификация:    ●   Асимметричные                        В        А
СопрограммыКлассификация:    ●   Асимметричные    ●   Симметричные                        В        А                   С
СопрограммыКлассификация:    ●   Асимметричные   ●   Без стековые (stackless)    ●   Симметричные        А                ...
СопрограммыКлассификация:    ●   Асимметричные   ●   Без стековые (stackless)    ●   Симметричные    ●   Стековые (stackfu...
СопрограммыЗачем?
Сопрограммы                 Зачем?●   Генераторы
Сопрограммы                      Зачем?●   Генераторы●   Задачи типа Производитель/Потребитель
Сопрограммы                      Зачем?●   Генераторы●   Задачи типа Производитель/Потребитель●   Кооперативная многопоточ...
Параллельная обработка данных  ●      Синхронная
Параллельная обработка данных  ●      Синхронная  ●      Асинхронная
Параллельная обработка данных  ●      Синхронная    ●                        Блокирующий I/O  ●      Асинхронная   ●      ...
Параллельная обработка данных  ●      Синхронная    ●                        Блокирующий I/O  ●      Асинхронная   ●      ...
Параллельная обработка данныхp1 = connect();read(p1, buff);p2 = connect();write(p2, buff);
Параллельная обработка данныхВыполнение остановилось здесь      p1 = connect();      read(p1, buff);      p2 = connect(); ...
Параллельная обработка данныхp1 = connect();read(p1, buff);p2 = connect();write(p2, buff);                   потоки
Параллельная обработка данных                   ✔ Написание программы в синхронном                     (интуитивном) стиле...
Параллельная обработка данных                   ✔ Написание программы в синхронном                     (интуитивном) стиле...
Параллельная обработка данных Reactor                   I/O while(true) {     e = r.events.dequeue();     r.dispatch(e); }...
Параллельная обработка данных Reactor                   I/O                                         ✔ Однопоточность - нет...
Параллельная обработка данных Reactor                   I/O                                         ✔ Однопоточность - нет...
Параллельная обработка данных Proactor                  I/O while(true) {     e = r.events.dequeue();     r.dispatch(e); }...
Параллельная обработка данных Proactor                  I/O                                        ✔ Однопоточность - нет ...
Параллельная обработка данных Proactor                  I/O                                        ✔ Однопоточность - нет ...
Параллельная обработка данных
Параллельная обработка данных
Boost.Asio„Thinking Asynchronously in C++“                                   Christopher Kohlhoff
Boost.AsioПоддерживает:●   Блокирующий I/O (read/write)●   Не блокирующий I/O (async_read/async_write)●   Асинхронную моде...
Boost.Asioasio::io_service io_service;// …tcp::socket socket(io_service);// ...socket.async_connect(       server_endpoint...
Boost.Asioasio::io_service io_service;// …tcp::socket socket(io_service);// ...socket.async_connect(       server_endpoint...
Boost.Asioasio::io_service io_service;// …                                   I/O objecttcp::socket socket(io_service);// ....
Boost.Asioasio::io_service io_service;// …tcp::socket socket(io_service);// ...                                   Ассинхро...
Boost.Asioasio::io_service io_service;// …tcp::socket socket(io_service);// ...socket.async_connect(       server_endpoint...
Boost.Asiosocket.async_connect(       server_endpoint,       your_completion_handler);                      io_service    ...
Boost.Asioio_service.run();                     io_service                                       work                     ...
Boost.Asioio_service.run();                     io_service                                        work                    ...
Boost.Asioio_service.run();                     io_service                                       work                     ...
Boost.Asioio_service.run();                            result                                             handler         ...
Boost.Asio                                  your_completion_handler(ec);io_service.run();                            resul...
Boost.AsioЕще не видите проблемы?
Boost.Asio     Еще не видите проблемы? А так?         your_completion_handler(ec);                                    your...
Boost.Asio Асинхронное программирование (в частности паттерны Reactor иProactor) требует чтобы задача, пусть и не сложная,...
Синхронное асинхронно
Синхронное асинхронно Введем ключевое слово yieldcoroutine server(...){    // ...    yield socket1.async_connect(         ...
Синхронное асинхронноРеализации сопрограмм для С++strcpy(to, from, count)                   Безстековые сопрограммыregiste...
Синхронное асинхронноРеализации сопрограмм для С++                                                Стековые сопрограммы ●  ...
Синхронное асинхронноРеализации сопрограмм для С++                                                   Стековые сопрограммы ...
Синхронное асинхронноBoost.Coroutines: ●   Stackfull сопрограммы ●   Cимметричные/асимметричные сопрограммы ●   Основа биб...
Синхронное асинхронноtypedef generator<leaf> generator_type;leaf tree_leaves (generator_type::self& self,  const node_type...
Синхронное асинхронноvoid foo(coro::coroutine<void()>::self& self){     typedef boost::asio::ip::tcp::socket socket_type; ...
Синхронное асинхронноBoost.Context: ●   Stackfull сопрограммы ●   Cимметричные/асимметричные сопрограммы ●   Основа библио...
Синхронное асинхронноfor (;;){    boost::asio::ip::tcp::socket socket( acceptor_.get_io_service() );    acceptor_.async_ac...
Синхронное асинхронноfor (;;){    boost::asio::ip::tcp::socket socket( acceptor_.get_io_service() );    acceptor_.async_ac...
Синхронное асинхронноfor (;;){    boost::asio::ip::tcp::socket socket( acceptor_.get_io_service() );    acceptor_.async_ac...
Синхронное асинхронноfor (;;){    boost::asio::ip::tcp::socket socket( acceptor_.get_io_service() );    acceptor_.async_ac...
Синхронное асинхронноreenter (this){     do{          socket_.reset(new tcp::socket(acceptor_->get_io_service()));        ...
Сопрограммы:✔ Сокращение числа обработчиков, упрощение логики;✔ Сохранение в некоторой мере синхронного стиля написания в ...
Сопрограммы:✔ Сокращение числа обработчиков, упрощение логики;✔ Сохранение в некоторой мере синхронного стиля написания в ...
Подробности: https://github.com/olk/boost.context/tree/master/libs/context, Boost.Context http://www.crystalclearsoftware....
Вопросы
Upcoming SlideShare
Loading in …5
×

CiklumCPPSat: Eugene Kulak "Stackless/stackfull coroutines and boost.asio"

942 views

Published on

CPP Saturday in Dnepropetrovsk, November, 19.

Published in: Education
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
942
On SlideShare
0
From Embeds
0
Number of Embeds
17
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

CiklumCPPSat: Eugene Kulak "Stackless/stackfull coroutines and boost.asio"

  1. 1. Стековые/безстековые сопрограммы и Boost.Asio Eugene Kulak keu@cilkum.net C++ Saturday, Nov 2011
  2. 2. Сопрограммы
  3. 3. Сопрограммы„ Подпрограммы – это частные случаи более общих программныхкомпонентов, называемых сопрограммами. В противоположностьнессиметричной связи между главной программой и подпрограммой, междусопрограммами, которые вызывают одна другую, существует полнаясимметрия. “ Д.Кнут, «Искусство программирования»
  4. 4. Сопрограммыподпрограмма подпрограмма
  5. 5. Сопрограммыподпрограмма подпрограмма
  6. 6. Сопрограммыподпрограмма подпрограмма
  7. 7. Сопрограммысопрограмма подпрограмма
  8. 8. Сопрограммысопрограмма подпрограмма
  9. 9. Сопрограммысопрограмма подпрограмма
  10. 10. СопрограммыСтэк А В С
  11. 11. СопрограммыАВС
  12. 12. СопрограммыАВС
  13. 13. СопрограммыАВС
  14. 14. СопрограммыАВС
  15. 15. СопрограммыКлассификация: ● Асимметричные В А
  16. 16. СопрограммыКлассификация: ● Асимметричные ● Симметричные В А С
  17. 17. СопрограммыКлассификация: ● Асимметричные ● Без стековые (stackless) ● Симметричные А В
  18. 18. СопрограммыКлассификация: ● Асимметричные ● Без стековые (stackless) ● Симметричные ● Стековые (stackfull) А В
  19. 19. СопрограммыЗачем?
  20. 20. Сопрограммы Зачем?● Генераторы
  21. 21. Сопрограммы Зачем?● Генераторы● Задачи типа Производитель/Потребитель
  22. 22. Сопрограммы Зачем?● Генераторы● Задачи типа Производитель/Потребитель● Кооперативная многопоточность (Псевдо-многопоточность в одном потоке)
  23. 23. Параллельная обработка данных ● Синхронная
  24. 24. Параллельная обработка данных ● Синхронная ● Асинхронная
  25. 25. Параллельная обработка данных ● Синхронная ● Блокирующий I/O ● Асинхронная ● Не блокирующий I/O
  26. 26. Параллельная обработка данных ● Синхронная ● Блокирующий I/O ● Асинхронная ● Не блокирующий I/O
  27. 27. Параллельная обработка данныхp1 = connect();read(p1, buff);p2 = connect();write(p2, buff);
  28. 28. Параллельная обработка данныхВыполнение остановилось здесь p1 = connect(); read(p1, buff); p2 = connect(); write(p2, buff);
  29. 29. Параллельная обработка данныхp1 = connect();read(p1, buff);p2 = connect();write(p2, buff); потоки
  30. 30. Параллельная обработка данных ✔ Написание программы в синхронном (интуитивном) стилеp1 = connect(); ✔ Поддежка многоядерных системread(p1, buff);p2 = connect();write(p2, buff);
  31. 31. Параллельная обработка данных ✔ Написание программы в синхронном (интуитивном) стилеp1 = connect(); ✔ Поддежка многоядерных системread(p1, buff); ✗ Проблемы синхронизацииp2 = connect(); ✗ Число потоков сильно ограниченоwrite(p2, buff);
  32. 32. Параллельная обработка данных Reactor I/O while(true) { e = r.events.dequeue(); r.dispatch(e); } read_h(...) { read(s,buff) }r.registerHandler( connect_h(...) events::Read, { read_h); }
  33. 33. Параллельная обработка данных Reactor I/O ✔ Однопоточность - нет проблем while(true) синхронизации { ✔ Поддержка новой задачи дешевле e = r.events.dequeue(); создания потока r.dispatch(e); } read_h(...) { read(s,buff) }r.registerHandler( connect_h(...) events::Read, { read_h); }
  34. 34. Параллельная обработка данных Reactor I/O ✔ Однопоточность - нет проблем while(true) синхронизации { ✔ Поддержка новой задачи дешевле e = r.events.dequeue(); создания потока r.dispatch(e); ✗ Большую задачу приходится разбивать на } множество мелких. ✗ Одна задача может повесить всю систему read_h(...) { read(s,buff) }r.registerHandler( connect_h(...) events::Read, { read_h); }
  35. 35. Параллельная обработка данных Proactor I/O while(true) { e = r.events.dequeue(); r.dispatch(e); } read_h(...) { }read(s, read_h, buff); connect_h(...) { }
  36. 36. Параллельная обработка данных Proactor I/O ✔ Однопоточность - нет проблем while(true) синхронизации { ✔ Поддержка новой задачи дешевле e = r.events.dequeue(); создания потока r.dispatch(e); ✔ Одновременное выполнение кода и } выполнение операций I/O read_h(...) { }read(s, read_h, buff); connect_h(...) { }
  37. 37. Параллельная обработка данных Proactor I/O ✔ Однопоточность - нет проблем while(true) синхронизации { ✔ Поддержка новой задачи дешевле e = r.events.dequeue(); создания потока r.dispatch(e); ✔ Одновременное выполнение кода и } выполнение операций I/O ✗ Необходимость управлять буферами read_h(...) { }read(s, read_h, buff); connect_h(...) { }
  38. 38. Параллельная обработка данных
  39. 39. Параллельная обработка данных
  40. 40. Boost.Asio„Thinking Asynchronously in C++“ Christopher Kohlhoff
  41. 41. Boost.AsioПоддерживает:● Блокирующий I/O (read/write)● Не блокирующий I/O (async_read/async_write)● Асинхронную модель Proactor● Синхронизацию обработки сообщений (io_service::strand)● STL-like потоки (streambuf)
  42. 42. Boost.Asioasio::io_service io_service;// …tcp::socket socket(io_service);// ...socket.async_connect( server_endpoint, your_completion_handler);// …io_service.run();
  43. 43. Boost.Asioasio::io_service io_service;// …tcp::socket socket(io_service);// ...socket.async_connect( server_endpoint, your_completion_handler);// …io_service.run();
  44. 44. Boost.Asioasio::io_service io_service;// … I/O objecttcp::socket socket(io_service);// ...socket.async_connect( server_endpoint, your_completion_handler);// …io_service.run();
  45. 45. Boost.Asioasio::io_service io_service;// …tcp::socket socket(io_service);// ... Ассинхронная операцияsocket.async_connect( server_endpoint, your_completion_handler);// …io_service.run();
  46. 46. Boost.Asioasio::io_service io_service;// …tcp::socket socket(io_service);// ...socket.async_connect( server_endpoint, your_completion_handler);// …io_service.run();
  47. 47. Boost.Asiosocket.async_connect( server_endpoint, your_completion_handler); io_service work handler Операционная система
  48. 48. Boost.Asioio_service.run(); io_service work handler Операционная система
  49. 49. Boost.Asioio_service.run(); io_service work notifies handler Операционная система
  50. 50. Boost.Asioio_service.run(); io_service work handler Операционная система
  51. 51. Boost.Asioio_service.run(); result handler io_service dequeues work handler Операционная система
  52. 52. Boost.Asio your_completion_handler(ec);io_service.run(); result handler io_service Операционная система
  53. 53. Boost.AsioЕще не видите проблемы?
  54. 54. Boost.Asio Еще не видите проблемы? А так? your_completion_handler(ec); your_completion_handler(ec);your_completion_handler(ec); your_completion_handler(ec); your_completion_handler(ec); your_completion_handler(ec); your_completion_handler(ec); your_completion_handler(ec); your_completion_handler(ec your_completion_handler(ec); your_completion_handler(ec); your_completion_handler(ec); your_completion_handler(ec); your_completion_handler(ec); your_completion_handler(ec); your_completion_handler(ec); your_completion_handler(ec); your_completion_handler(ec); your_completion_handler(ec); your_completion_handler(ec); your_completion_handler(ec); your_completion_handler(ec); your_completion_handler(ec);
  55. 55. Boost.Asio Асинхронное программирование (в частности паттерны Reactor иProactor) требует чтобы задача, пусть и не сложная, была разбита нанесколько подзадач. Иногда такое деление неприемлимо,трудозатратно и делает логику в целом трудной для понимания. Есть ли выход? Представим себе алгоритм описанный как синхронный, ноработающий асинхронно. Что-то способное приостанавливать своевыполнение и продолжать его позже. Например – сопрограмма.
  56. 56. Синхронное асинхронно
  57. 57. Синхронное асинхронно Введем ключевое слово yieldcoroutine server(...){ // ... yield socket1.async_connect( server_endpoint, your_completion_handler); yield socket1->async_read_some(buffer(*buffer_),*this); yield socket2.async_connect( server_endpoint, your_completion_handler); yield socket2->async_write_some(buffer(*buffer_), *this); // ...}
  58. 58. Синхронное асинхронноРеализации сопрограмм для С++strcpy(to, from, count) Безстековые сопрограммыregister char *to, *from; (протопотоки)register count;{ register n = (count + 7) / 8; if (!count) return; switch (count % 8) { case 0: do { *to = *from++; case 7: *to = *from++; case 6: *to = *from++; case 5: *to = *from++; case 4: *to = *from++; case 3: *to = *from++; case 2: *to = *from++; case 1: *to = *from++; } while (--n > 0); }} Устройство „Даффа“
  59. 59. Синхронное асинхронноРеализации сопрограмм для С++ Стековые сопрограммы ● POSIX ucontext; ● Windows fibers (легковесные потоки); ● Платформенно зависимые игры со стеком через asm.
  60. 60. Синхронное асинхронноРеализации сопрограмм для С++ Стековые сопрограммы ● POSIX swapcontext; ● Windows fibers (легковесные потоки); ● Платформенно зависимые игры со стеком через asm. Существующие: ● Boost.Coroutines ● Coro ● Boost.Context ● LibCoroutine ● LibCoro ● State threads
  61. 61. Синхронное асинхронноBoost.Coroutines: ● Stackfull сопрограммы ● Cимметричные/асимметричные сопрограммы ● Основа библиотеки – класс coroutine ● Сопрограммы разделены на тело (ф-цию) и состояние ● Не развивается с 2009 года
  62. 62. Синхронное асинхронноtypedef generator<leaf> generator_type;leaf tree_leaves (generator_type::self& self, const node_type& node){ if(is_leaf(node)) { self.yield(boost::get<leaf_type>(tree)); } else { tree_leaves(self, boost::get<node_type>.first); tree_leaves(self, boost::get<node_type>.second); } self.exit();}bool same_fringe(const element& tree1, const element& tree2) { generator_type tree_leaves_a(boost::bind(tree_leaves, _1, tree1)); generator_type tree_leaves_b(boost::bind(tree_leaves, _1, tree2)); while(tree_leaves_a && tree_leaves_b) { if(tree_leaves_a() != tree_leaves_b()) return false; } return true && (!tree_leaves_b && !tree_leaves_a);}
  63. 63. Синхронное асинхронноvoid foo(coro::coroutine<void()>::self& self){ typedef boost::asio::ip::tcp::socket socket_type; typedef boost::asio::error error_type; char token[1024]; socket_type source; coro::future<error_type, std::size_t> read_result(self); //... asio::async_read(source, boost::asio::buffer(token, 1024), coro::make_callback(read_result)); //... coro::wait(source); if(source->get<0>()) { std::cout <<"Errorn!"; } else { std::cout <<"Written "<<source->get<1>()<<" bytes"; }}
  64. 64. Синхронное асинхронноBoost.Context: ● Stackfull сопрограммы ● Cимметричные/асимметричные сопрограммы ● Основа библиотеки – класс context ● Библиотека общего назначения, на ее основе разрабатывается функционал boost.Fibers, „продолжений“ и генераторов (enumeration) ● С весны 2011 года находится на ревью по включению ее в состав Boost.
  65. 65. Синхронное асинхронноfor (;;){ boost::asio::ip::tcp::socket socket( acceptor_.get_io_service() ); acceptor_.async_accept( socket, boost::bind( & server::operator(), this-> shared_from_this(), _1, 0) ); suspend(); while (!ec_) { boost::array< char, 1024 > buffer; socket.async_read_some( boost::asio::buffer( buffer), boost::bind( & server::operator(), this->shared_from_this(), _1, _2) ); suspend(); if ( ec_) break; boost::asio::async_write( socket, boost::asio::buffer( buffer, n_), boost::bind( & server::operator(), this->shared_from_this(), _1, _2) ); suspend(); }}...void operator()( boost::system::error_code ec, size_t n){ ec_ = ec; n_ = n; resume();}
  66. 66. Синхронное асинхронноfor (;;){ boost::asio::ip::tcp::socket socket( acceptor_.get_io_service() ); acceptor_.async_accept( socket, boost::bind( & server::operator(), this-> shared_from_this(), _1, 0) ); suspend(); while (!ec_) { boost::array< char, 1024 > buffer; socket.async_read_some( boost::asio::buffer( buffer), boost::bind( & server::operator(), this->shared_from_this(), _1, _2) ); suspend(); if ( ec_) break; boost::asio::async_write( socket, boost::asio::buffer( buffer, n_), boost::bind( & server::operator(), this->shared_from_this(), _1, _2) ); suspend(); }}...void operator()( boost::system::error_code ec, size_t n){ ec_ = ec; n_ = n; resume();}
  67. 67. Синхронное асинхронноfor (;;){ boost::asio::ip::tcp::socket socket( acceptor_.get_io_service() ); acceptor_.async_accept( socket, boost::bind( & server::operator(), this-> shared_from_this(), _1, 0) ); suspend(); while (!ec_) { boost::array< char, 1024 > buffer; socket.async_read_some( boost::asio::buffer( buffer), boost::bind( & server::operator(), this->shared_from_this(), _1, _2) ); suspend(); if ( ec_) break; boost::asio::async_write( socket, boost::asio::buffer( buffer, n_), boost::bind( & server::operator(), this->shared_from_this(), _1, _2) ); suspend(); }}...void operator()( boost::system::error_code ec, size_t n){ ec_ = ec; n_ = n; resume();}
  68. 68. Синхронное асинхронноfor (;;){ boost::asio::ip::tcp::socket socket( acceptor_.get_io_service() ); acceptor_.async_accept( socket, boost::bind( & server::operator(), this-> shared_from_this(), _1, 0) ); suspend(); while (!ec_) { boost::array< char, 1024 > buffer; socket.async_read_some( boost::asio::buffer( buffer), boost::bind( & server::operator(), this->shared_from_this(), _1, _2) ); suspend(); if ( ec_) break; boost::asio::async_write( socket, boost::asio::buffer( buffer, n_), boost::bind( & server::operator(), this->shared_from_this(), _1, _2) ); suspend(); }}...void operator()( boost::system::error_code ec, size_t n){ ec_ = ec; n_ = n; resume();}
  69. 69. Синхронное асинхронноreenter (this){ do{ socket_.reset(new tcp::socket(acceptor_->get_io_service())); yield acceptor_->async_accept(*socket_, *this); fork server(*this)(); } while (is_parent()); buffer_.reset(new boost::array<char, 8192>); request_.reset(new request); do { yield socket_->async_read_some(boost::asio::buffer(*buffer_), *this); boost::tie(valid_request_, boost::tuples::ignore) = request_parser_.parse(*request_, buffer_->data(), buffer_->data() + length); } while (boost::indeterminate(valid_request_)); reply_.reset(new reply); if (valid_request_) { request_handler_(*request_, *reply_); } else { *reply_ = reply::stock_reply(reply::bad_request); } yield boost::asio::async_write(*socket_, reply_->to_buffers(), *this); socket_->shutdown(tcp::socket::shutdown_both, ec);}
  70. 70. Сопрограммы:✔ Сокращение числа обработчиков, упрощение логики;✔ Сохранение в некоторой мере синхронного стиля написания в асинхронной модели;
  71. 71. Сопрограммы:✔ Сокращение числа обработчиков, упрощение логики;✔ Сохранение в некоторой мере синхронного стиля написания в асинхронной модели;✗ Отсутствие поддержки в языке;✗ Сложность реализации;✗ Подверженность ошибкам;
  72. 72. Подробности: https://github.com/olk/boost.context/tree/master/libs/context, Boost.Context http://www.crystalclearsoftware.com/soc/coroutine/index.html, Boost.Coroutines http://www.boost.org/doc/libs/1_48_0/doc/html/boost_asio.html Boost.Asio http://www.inf.puc-rio.br/~roberto/docs/MCC15-04.pdf Revisiting Coroutines http://www.kegel.com/c10k.html C10k Problem
  73. 73. Вопросы

×