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
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Takatoshi Kondo
April 19, 2024
Programming
360
0
Share
Boost.Asioにおけるcoroutineの活用法
C++20以降で使える、asioとcoroutineの組み合わせかたについて。
特に非同期処理の完了を複数同時待ちする方法について紹介。
Takatoshi Kondo
April 19, 2024
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
370
Other Decks in Programming
See All in Programming
JJUG CCC 2026 Spring: JSpecify で実現する Kotlin フレンドリーな Java API 設計
ternbusty
1
140
AI時代の仕事技芸論 — ソフトウェア開発で「遊ぶように働く」職人的熟達のすすめ
kuranuki
1
610
TSKaigi Night Talks 2026_TypeScriptでサプライチェーンの整合性を型に閉じ込める
geekplus_tech
0
300
セキュリティの専門家じゃなくてもできる。「セキュリティ意識」をアップデートして サプライチェーン攻撃への耐性を高めよう。
tk3fftk
5
630
AI 時代のソフトウェア設計の学び方
masuda220
PRO
29
12k
メソッドのジェネリクスでGoの夢は広がるか? / Kyoto.go #65
utgwkk
3
550
net-httpのHTTP/2対応について
naruse
0
440
tsserverとは何だったのか、これからどうなるのか
nowaki28
1
450
IBM Bobを活用したレガシーアプリの最新化
oniak3ibm
PRO
1
170
Inside Stream API
skrb
1
640
プロパティの順序で型推論が壊れる!? TypeScript6.0の修正からContext-Sensitivityの仕組みを追う
bicstone
2
1.3k
プラグインで拡張される Context をtype-safe にする難しさと設計判断
kazupon
2
590
Featured
See All Featured
A Tale of Four Properties
chriscoyier
163
24k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
62k
Reflections from 52 weeks, 52 projects
jeffersonlam
356
21k
What the history of the web can teach us about the future of AI
inesmontani
PRO
1
600
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.3k
Scaling GitHub
holman
464
140k
Utilizing Notion as your number one productivity tool
mfonobong
4
310
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.3k
Navigating Weather and Climate Data
rabernat
0
210
The Cost Of JavaScript in 2023
addyosmani
55
10k
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
190
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
550
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