tokioはIO-boundな処理を書くためのものであって、CPU-boundな処理を並列化(マルチコアの活用?)するためのものではない。
Tokio is designed for IO-bound applications where each individual task spends most of its time waiting for IO.
だいたいNode.jsなどのevent loopと近い概念だと思えば良い
tokioはIO-boundな処理を書くためのものであって、CPU-boundな処理を並列化(マルチコアの活用?)するためのものではない。
Tokio is designed for IO-bound applications where each individual task spends most of its time waiting for IO.
だいたいNode.jsなどのevent loopと近い概念だと思えば良い
このブログが詳しくてよかった
https://tech-blog.optim.co.jp/entry/2019/11/08/163000
Rustは組み込みなどでも動くため、(Goのgoroutineのような)非同期処理をいい感じに管理してくれるグリーンスレッド的なものは用意されてない。
async/awaitが実装されて、Futureが実装されたけど
それを実行するランタイムは実は用意されてない!
IO的に読み取り可能であることを示すtraint
https://doc.rust-lang.org/std/io/trait.Read.html
非同期に対応したものは
#tokio
tokioで非同期的にread可能なものはtokio::io::AsyncRead traitを実装している
これは poll_read というメソッドを持っていて、読み取り可能(OK)か、Pendingかなどの情報が返ってくる
とはいえ、直接これを呼ぶことはほぼなくて、基本AsyncReadExt拡張メソッドを使う
axumでファイルの内容をストリームで返す方法
axumの Body::from_stream に Streamを渡す
Streamは S: TryStream + Send + 'static,
らしい
TryStream
が使おうとしたのがstd::fs::Fileだったのでそれをtokio::fs::Fileに変換しないとtokio::io::AsyncRead traitを満たせなくて、ファイルからファイルを作ってストリームを作って……という冗長なコードになった
https://docs.rs/futures-core/0.3.21/futures_core/stream/trait.Stream.html
https://www.qovery.com/blog/a-guided-tour-of-streams-in-rust/
非同期なIteratorのようなもの
Futureと同様に poll_next
で次のアイテムがあるか、まだ準備中か返す
もっと具体的に言うと、 Poll<Option<Self::Item>>
を返す
tokioのところが作っているWeb Framework
IntoResponse
traitを実装しているあらゆるものをHTTP responseとして返せる
https://docs.rs/axum/latest/axum/response/index.html
便利ではある反面、一体何の型がどうresponseになるのか非常にわかりづらかった
例)axum ファイルをストリームで返す
https://grod.es/posts/single-threaded_async_rust
この記事がちょっと面白かったので雑に要約
ネットワークから情報を取得し続けて、それをUIに反映するTUI appが書きたい
単純な制御なのでシングルスレッドによる非同期処理で十分だと感じた
tokioの flavor="current_thread"
を使ってシングルスレッドにした
#tokio
yield_now を呼んだからといって必ず他のタスクに切り替わるという保証はない。
ランタイム次第では、同じタスクにすぐ戻ってきてしまうこともある
the runtime may choose to poll the task that just ran yield_now() again immediately without polling any other tasks first.
Goのチャネルのようにメッセージパッシングによるデータのやり取りをするもの
multi-producer, single-consumer
std::sync::mpsc
await可能なtokio版もある
single-producer, single-consumer
#tokio
通常のMutex (std::sync::Mutex
) はロック待ちのときスレッドをブロックする
一方、tokio::sync::Mutex
はロック待ちをawaitできる
std::sync::Mutexと比べて何が違うのか?
どう使い分けるのか?
#tokio
thread::spawn関数と似た使い方だが、OSスレッドではなくtokioの軽量タスクとして立ち上がる
タスクは、スケジューラによって管理される実行単位です。タスクを spawn すると、Tokio のスケジューラにそれが登録され、適切なタイミングでタスクが実行されることが保証されます。spawn されたタスクは、spawn されたスレッドと同一のスレッド上で実行されることもあれば、ランタイム上の異なるスレッドで実行されることもあります。spawn されたあとにスレッド間を行き来することもあります
#tokio
たとえば TcpListener
とかは std::net
にもあるし tokio::net
にもある
これはどういう関係か?
Many of Tokio's types are named the same as their synchronous equivalent in the Rust standard library. When it makes sense, Tokio exposes the same APIs as std but using async fn.
#tokio
cfg_rt_multi_thread! {
impl Builder {
fn build_threaded_runtime(&mut self) -> io::Result<Runtime> {
use crate::loom::sys::num_cpus;
tokio連携で作りたい場合、tokio_util::codec::FramedReadを使うとよい
例:先頭2byteが長さで、そのあとがpayloadのFrameを読み取る
use std::io::Read;
fn main() {
let mut input = &[
#tokio
std::thread::sleepでacceptを待っていたのがダメだった、、それじゃブロッキングされちゃうじゃん
ちゃんと tokio::time::sleep().await でコンテキストスイッチを発生させないと・・。
#tokio
この関数は現在タスクを実行しているスレッドに溜まっている非同期タスクを別のスレッドに委任し、 現在のスレッドで同期タスクを実行します。 現在のスレッドでタスクを実行するため戻り値はFutureではなく同期タスクの戻り値そのものです
https://tech-blog.optim.co.jp/entry/2019/11/08/163000
#tokio
https://github.com/tokio-rs/tokio/blob/master/examples/proxy.rs