pagetakaBlog

最近リフォームと鳥取県日南町の記事多め。写真、PC、ネット等の話題も

Rust+MariaDB:非同期(tokio+sqlx)に変更し、待ち時間解消とバグ潰し

前説:Rust+TCP/IP接続実現

これまでの記事で、Linux_mint+MariaDB+Rust+mysql+TCP/IPを実現しました。Rust+TCP/IP実現まで、爺はかなり疲れたですけど、できて良かったです。
まとめ:Linux Mint で MariaDB 接続トラブル解消記(Rust対応) - pagetakaBlog
追補:Linux_mint+MariaDB+Rust+TCP/IP+mysql 準備編 - pagetakaBlog

Rust+MariaDBのゴールはまだ先にあるのかと

RustでRDB(リレーショナルデータベース)操作するとなると、目指す先には、課題が随分あると思う爺です。Linux_mint+MaraiDB+Rust+sqlx+tokio+query_as!+struct。 日付、Decimalなど型処理まで含めたら断崖絶壁かもしれませぬ。
「無料OS、RDB、Rustで、非同期処理し構造体に収めたい」という妄想を現実に引き寄せたい爺です。

今回は、非同期接続・処理に必要な最低限「tokio+sqlx」を実現します(query_as!、structなどはお預け)。

同期接続のプログラム(main.rs)と依存関係(Cargo.toml)を、最小限の修正で、非同期に変更します。
同期用プログラム改修で非同期用に変更します。

Cargo.toml の修正

dependencies欄の、同期用のmysqlドライバの記述を消去し、非同期用のsqlx+tokioに変更

  • Cargo.toml ↓
(package略)

[dependencies] # 書けば、コンパイル時に公式からDL、インストールしてくれる
sqlx = { version = "0.7", features = ["runtime-tokio", "mysql"] }
tokio = { version = "1", features = ["full"] }

main.rs の修正後プログラム

説明よりまず動かしてみる、ですね。

use sqlx::mysql::MySqlPoolOptions;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("Hello, async sqlx!");

    let url = "mysql://user名:password@192.168.x.x:3306/db_name";

    // 非同期コネクションプール
    let pool = MySqlPoolOptions::new()
        .max_connections(5)
        .connect(url)
        .await?;

    // SELECT id, val FROM test LIMIT 1 
    let row = sqlx::query_as::<_, (i32, i32)>(
        "SELECT id, val FROM test LIMIT 1"
    )
    .fetch_optional(&pool)
    .await?;

    match row {
        Some((id, val)) => println!("id:{}, val:{}", id, val),
        None => println!("データがありません"),
    }

    Ok(())
}

アレコレの説明(だいぶcopilotに助けてもらいました)

同期TCP/IP接続でDATABASE_URLをすでに実行

同期接続でTCP/IPを使用してますので、非同期処理導入に際し、「IPアドレス(database_url)」変更ありません。同期から非同期に変更するとき時々話題に上がるRDBの「IPアドレス(database_url)」ですが、予習・予行がすんでました。

非同期処理はRust側の待ち時間活用優等生

同期/非同期処理の違いは、Rust側待ち時間の使い方です。爺は、MariaDB側のコトかと妄想してましたが、Copilotに「Rust が待ち時間をどう扱うか」 と教えてもらいました。

フードコートで例えてみます。

  • 非同期:料理出来たらスマホに連絡あるので、それまでは自由に席で過ごせる
  • 同期:カウンターで注文し、料理ができるまでそのまま待つ

スマホに連絡来るなら、待ち時間にSNS発信するなど隙間時間利用できます。

Rustプログラム内でも同じで、

  • 非同期:MariaDBへ接続・処理を依頼したら、結果が返えるまで、別処理(主にプログラム後続行)を進行しつつ、呼出しを待つ
  • 同期:MariaDBへ接続・処理を依頼したら、結果が返るまでジッと待つので、隙間時間利用ができてない

という状態のようです。「スマホ呼出し」って、爺的にはずいぶん新しいコトでっす。待ち時間にほかの作業進行。これは、プログラム全体のスピードUPに結び付く可能性が高いですよね。ぜひ、マスターしたい「非同期」です。

同期で書いたプログラムを多少修正すれば、非同期処理になり、待ち時間が減り、Rustらしさに「半歩」近づきました。

「sqlx」はバグ潰しに獅子奮迅の活躍

「sqlx」は追加の道具(crate)で、Pythonのパッケージをインストールして使うのと同じ感覚です。
非同期処理では、tokio+sqlx の選択は「ほぼほぼ定番」のようです。
sqlxのありがた味は「バグ潰し」です。

  • コンパイル時に密かにRDBに接続し
  • SQLバグが無いかチェックしてくれ
  • 実行したら落ちる、という悲劇を回避

Rustの厳格さを体現した逸品です。

「tokio」は非同期処理の要

Rustの非同期処理は、「async/await」の文法、実際に動かす「tokio」エンジンの組合せでなりたってます。

  • async/await:Rustが「料理できたらスマホに連絡してネ」というオヤクソクのコトバ
  • tokio:その通知を受取り、「連絡通知を頂いたら、すぐRustさんに知らせまっす」と段取りしてくれる「呼出し係」

async/await + tokio が Rustと一緒になって非同期処理してくれてます。

query_as!+struct など先はまだある...

前記事の「同期」から、今回「非同期」へと進行し、半歩前進できました。この次は、マクロquery_as!と構造体structを使いよりRustらしく前進させるのが、爺の妄想です。