使用benjamin-batchly實現Rust非同步批處理 - alexheretic

banq發表於2022-06-08

有時,與其同時做很多小事,不如將它們捆綁在一起,一次完成,作為一個批處理。所以在星期四早上的一個銀行假期裡,我很早就醒了(主要是因為我 1 歲男孩的尖叫聲)並且(在尖叫聲停止後)寫了一個crate 來幫助做到這一點:benjamin_batchly

示例:插入資料庫
資料庫最佳化的一個反覆出現的主題是減少對資料庫的“旅行”。傳送 1 條包含 N 項的胖訊息通常比傳送 N 條僅包含 1 項的瘦訊息要快。

考慮一個我們想要插入資料庫的 crud 風格的建立請求。

async fn handle_create_foo(db: &Db, data: CreateFooRequest) -> Result<(), Error> {
    let db_item = DbItem::from(data);
    db.insert(db_item).await?;
    Ok(())
}

因此,對於每個CreateFooRequest,我們將在我們的資料庫中插入一個專案。我們可以使用BatchMutex對它們進行批處理。

use benjamin_batchly::{BatchMutex, BatchResult};

async fn handle_create_foo(
    batch_mutex: &BatchMutex<(), DbItem>,
    db: &Db,
    data: CreateFooRequest,
) -> Result<(), Error> {
    let db_item = DbItem::from(data);
    match batch_mutex.submit((), db_item).await {
        BatchResult::Work(mut batch) => {
            db.bulk_insert(&batch.items).await?;
            batch.notify_all_done();
            Ok(())
        }
        BatchResult::Done(_) => Ok(()),
        BatchResult::Failed => Err(Error::BatchFailed),
    }
}

提交到BatchMutex提供 3 個非同步結果。
  • Work :一批 1 個或多個專案,包括提交的專案,應處理。
  • Done:提交的專案由另一個提交者批次處理並通知完成。
  • Failed:提交的專案由另一個提交者批次處理,但在通知完成之前被丟棄。

因此,如果在批處理進行時有 100 個CreateFooRequest請求進入,它們將在submit處等待。上一批完成後,所有等待提交的內容將成為下一批。1 次呼叫將返回BatchResult::Work並且在batch.notify_all_done()呼叫後 99 次將返回BatchResult::Done。

注意:在示例中,我使用單位型別 () 作為submit的第一個引數。這是可用於分割槽批處理的“批處理金鑰”。只有使用相同批次金鑰提交的專案才會捆綁在一起,這在更一般的情況下很有用。

注意(2):也支援單獨的專案返回值,檢視文件以獲取更多資訊。

相關文章