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
300
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
360
Other Decks in Programming
See All in Programming
Apache Iceberg V3 and migration to V3
tomtanaka
0
170
LLM Observabilityによる 対話型音声AIアプリケーションの安定運用
gekko0114
2
440
QAフローを最適化し、品質水準を満たしながらリリースまでの期間を最短化する #RSGT2026
shibayu36
2
4.4k
なるべく楽してバックエンドに型をつけたい!(楽とは言ってない)
hibiki_cube
0
140
並行開発のためのコードレビュー
miyukiw
0
1.1k
【卒業研究】会話ログ分析によるユーザーごとの関心に応じた話題提案手法
momok47
0
200
「ブロックテーマでは再現できない」は本当か?
inc2734
0
1k
KIKI_MBSD Cybersecurity Challenges 2025
ikema
0
1.3k
ぼくの開発環境2026
yuzneri
0
240
副作用をどこに置くか問題:オブジェクト指向で整理する設計判断ツリー
koxya
1
610
Gemini for developers
meteatamel
0
100
AIによる高速開発をどう制御するか? ガードレール設置で開発速度と品質を両立させたチームの事例
tonkotsuboy_com
7
2.4k
Featured
See All Featured
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.1k
Neural Spatial Audio Processing for Sound Field Analysis and Control
skoyamalab
0
170
Leading Effective Engineering Teams in the AI Era
addyosmani
9
1.6k
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
110
How to audit for AI Accessibility on your Front & Back End
davetheseo
0
180
Testing 201, or: Great Expectations
jmmastey
46
8.1k
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
200
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
128
55k
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
67
AI Search: Where Are We & What Can We Do About It?
aleyda
0
7k
How to Talk to Developers About Accessibility
jct
2
140
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
1
1.4k
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