Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Boost.Asioにおけるcoroutineの活用法
Search
Takatoshi Kondo
April 19, 2024
Programming
0
200
Boost.Asioにおけるcoroutineの活用法
C++20以降で使える、asioとcoroutineの組み合わせかたについて。
特に非同期処理の完了を複数同時待ちする方法について紹介。
Takatoshi Kondo
April 19, 2024
Tweet
Share
More Decks by Takatoshi Kondo
See All by Takatoshi Kondo
boost::multi_index version >= 1.56.0 internal structure and iteration algorithm for gdb Boost-Prerry-Printer
redboltz
0
340
Other Decks in Programming
See All in Programming
The Evolution of Enterprise Java with Jakarta EE 11 and Beyond
ivargrimstad
0
540
What's new in AppKit on macOS 26
1024jp
0
180
[SRE NEXT] 複雑なシステムにおけるUser Journey SLOの導入
yakenji
0
810
Startups on Rails in Past, Present and Future–Irina Nazarova, RailsConf 2025
irinanazarova
0
310
PHPカンファレンス関西2025 基調講演
sugimotokei
5
1k
Bedrock AgentCore ObservabilityによるAIエージェントの運用
licux
8
360
Comparing decimals in Swift Testing
417_72ki
0
100
ソフトウェア設計とAI技術の活用
masuda220
PRO
25
6.9k
可変性を制する設計: 構造と振る舞いから考える概念モデリングとその実装
a_suenami
7
1k
顧客の画像データをテラバイト単位で配信する 画像サーバを WebP にした際に起こった課題と その対応策 ~継続的な取り組みを添えて~
takutakahashi
4
1.4k
AI Ramen Fight
yusukebe
0
120
MCPを使ってイベントソーシングのAIコーディングを効率化する / Streamlining Event Sourcing AI Coding with MCP
tomohisa
0
190
Featured
See All Featured
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
53
2.9k
Designing for Performance
lara
610
69k
Code Review Best Practice
trishagee
69
19k
Statistics for Hackers
jakevdp
799
220k
Fashionably flexible responsive web design (full day workshop)
malarkey
407
66k
Faster Mobile Websites
deanohume
308
31k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
181
54k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
33
2.4k
We Have a Design System, Now What?
morganepeng
53
7.7k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
3.9k
[RailsConf 2023] Rails as a piece of cake
palkan
55
5.7k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
53k
Transcript
Boost.Asioにおける coroutineの活用法 C++20以降で使える、asioとcoroutineの組み合わせ 近藤 貴俊 redboltz
発表者について • 近藤貴俊 redboltz • Boost Libraries コントリビュータ • MQTT
(IoT分野でよく使われる軽量プロトコル) ライブラリ作者 async_mqtt, mqtt_cpp • 軽量シリアライズフォーマット MessagePack の CおよびC++ 版 msgpack-c メンテナ • stackoverflowでQ&A活動中 2/20
Boost.Asioとは? • Asynchronous IO で asio • 非同期処理の基盤となるメカニズムを提供 • 非同期処理の各種応用を提供
• ネットワーク通信 • タイマ • コンソール入出力 • シグナル • etc 3/20
非同期処理の完了を通知する手段 • コールバック • 関数、関数オブジェクト、ラムダ式 など • CompletionToken • use_future,
use_awaibale, deferred, experimental::use_promise など 4/20 本日のメインテーマ asioスタイルの非同期関数の例 ここに何を渡すかで戻り値の型が変わる
callback vs coroutine 5/20 https://godbolt.org/z/MfW5MoTcY https://godbolt.org/z/M7rMe6ren
6/20 coroutine callback VS
co_await 7/20 • 非同期処理の完了を待つことができる • どこで待てるのか 戻り値の型がawaitable<T> の関数の中 co_composedに渡すラムダ式の中
co_await 8/20 • なにを待てるのか 戻り値の型がawaitable<T> の関数呼び出し CompletionTokenとして、use_awaitableを渡した関数呼び出し CompletionTokenとして、deferredを渡した関数呼び出し CompletionTokenとして、use_promiseを渡した関数呼び出し
co_await 9/20 • どこでなにを待てるのか 戻り値の型がawaitable<T> の関数呼び出し CompletionTokenとして、use_awaitableを渡した関数呼び出し CompletionTokenとして、deferredを渡した関数呼び出し CompletionTokenとして、use_promiseを渡した関数呼び出し 戻り値の型がawaitable<T>
の関数の中 全て待てる https://godbolt.org/z/xEd4qWEj3
co_await 10/20 • どこでなにを待てるのか 戻り値の型がawaitable<T> の関数呼び出し CompletionTokenとして、use_awaitableを渡した関数呼び出し CompletionTokenとして、deferredを渡した関数呼び出し CompletionTokenとして、use_promiseを渡した関数呼び出し co_composedに渡すラムダ式の中
awaitable以外 待てる https://godbolt.org/z/dbfhdY7jG
co_composedのうれしさ 11/20 • CompletionTokenベースの関数内で co_awaitが使える • awaitableの連鎖を断ち切ることができる • ただし、co_composed関数の中からawaitableな関数は呼び出せない https://godbolt.org/z/snx1643b4
非awaitable非同期関数 awaitable非同期関数 非awaitable非同期関数 awaitable非同期関数 CompletionTokenBased
co_awaitとマルチウェイト 12/20 • 典型的なマルチウェイトのパターン • 複数の非同期関数を呼び出し、最初の結果が来たら他をキャンセルする • 例:タイムアウト付き受信処理 • 複数の非同期関数を呼び出し、全ての結果がそろってから処理を行う
• 例: メッセージの一斉配信処理 • 待つ要素の種類と数 • コンパイル時に決まっている • 例:1つの受信待ちに1つのタイムアウト • 実行時に決まる • 例:現在接続しているクライアント全員にメッセージ配信し、 全ての非同期送信の結果を待つ • awaitableか非awaitableかで方法が異なる マルチウェイトになっていない例 async_func1()の非同期処理の完了を待ってから async_func2()を開始してしまう 全部待ち ひとつ待ち 静的 動的 awaitable 非awaitable
13/20 https://godbolt.org/z/nxzPoEafz awaitableな非同期関数群のマルチウェイト 今ひとつ釈然としないが、こういう仕様 全部待ち 静的 awaitable co_awaitとマルチウェイト co_await (aaa()
&& bbb())
14/20 https://godbolt.org/z/5rb34T38Y co_awaitとマルチウェイト co_await (aaa() || bbb()) ひとつ待ち 静的 awaitable
15/20 https://godbolt.org/z/1Tx4rE75n co_awaitとマルチウェイト make_parallel_group(funcs...) wait_for_all() 全部待ち 静的 非awaitable
16/20 https://godbolt.org/z/hn8GMs1We co_awaitとマルチウェイト make_parallel_group(funcs...) wait_for_one() ひとつ待ち 静的 非awaitable
17/20 https://godbolt.org/z/c6ao6883c co_awaitとマルチウェイト make_parallel_group(vec) wait_for_all() 全部待ち 動的 非awaitable
18/20 https://godbolt.org/z/69zWs7M5G co_awaitとマルチウェイト make_parallel_group(vec) wait_for_one() ひとつ待ち 動的 非awaitable
co_awaitとマルチウェイト まとめ 19/20 要素数確定タイミング awaitable非同期関数 非awaitable非同期関数 コンパイル時 co_await (... &&
...) co_await (... || ...) co_await make_parallel_group( func1(deferred), func2(experimental::use_promise) ).async_wait( experimental::wait_for_all(), // experimental::wait_for_one(), deferred ); 実行時 調査した限り手段無し using op_type = decltype(post(exe, append(deferred, int{}))); std::vector<op_type> ops; for (int i = 0; i != 5; ++i) ops.push_back(post(exe, append(as::deferred, i*10))); auto [orders, values] = co_await experimental::make_parallel_group( ops ).async_wait( experimental::wait_for_all(), // experimental::wait_for_one(), deferred ); 全部待ち 非awaitable awaitable 静的 動的 ひとつ待ち 全部待ち ひとつ待ち 全部待ち ひとつ待ち
以上。時間があればBonus Slides 20/20
co_spawn • coroutineを起動する 21/20 #include <iostream> #include <boost/asio.hpp> namespace as
= boost::asio; as::awaitable<void> coro_main() { std::cout << "coro started" << std::endl; co_return; } int main() { as::io_context ioc; as::co_spawn( ioc.get_executor(), coro_main, as::detached ); ioc.run(); } ←callableを渡している https://godbolt.org/z/bjE4TrP3v #include <iostream> #include <boost/asio.hpp> namespace as = boost::asio; as::awaitable<void> coro_main() { std::cout << "coro started" << std::endl; co_return; } int main() { as::io_context ioc; as::co_spawn( ioc.get_executor(), coro_main(), as::detached ); ioc.run(); } https://godbolt.org/z/1dTxc66do ←awaitableを渡している
co_spawnの宣言 22/20 https://www.boost.org/doc/libs/1_84_0/doc/html/boost_asio/reference/co_spawn/overload1.html https://www.boost.org/doc/libs/1_84_0/doc/html/boost_asio/reference/co_spawn/overload5.html
CompletionToken指定時の注意 • 第1パラメタがboost::system::error_codeの場合の取り扱い • successのときは何も起こらず、その他errorの時、例外がthrowされる • これを防ぐには、as_tuple(deferred)のように、as_tupleで囲む こうすれば、successであってもerrorであっても、tupleの0番目の 要素として、 boost::system::error_codeが取得できる
23/20
CompletionToken指定時の戻り値の型 24/20 boost::asio::awaitable< void, boost::asio::any_io_executor > boost::asio::awaitable< void, boost::asio::any_io_executor >
boost::asio::deferred_async_operation< void (), boost::asio::detail::initiate_dispatch > boost::asio::experimental::promise< void (), boost::asio::basic_system_executor< boost::asio::execution::detail::blocking::possibly_t<0>, boost::asio::execution::detail::relationship::fork_t<0>, std::allocator<void> >, std::allocator<void> > https://godbolt.org/z/W9veEY35v boost::typeindex::type_id< decltype(as::post(as::deferred)) >().pretty_name() この部分を差し替えて出力
co_composedとexecutor 25/20 • co_composedがどのexecutorで動いているのか https://godbolt.org/z/vs9cGdEeK