You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Tokio实现令牌消耗式速率限制?

现成解决方案推荐

针对你需要的一次性消耗式令牌场景,不需要自己实现原子变量+重试,Rust生态里有几种现成方案:

1. 异步通道(async-channel)

用异步通道模拟令牌池,预先向通道发送若干令牌,每次recv().await获取并消耗令牌,通道空时自动阻塞等待新令牌:

use async_channel::{unbounded, Receiver};

#[tokio::main]
async fn main() {
    let (sender, receiver) = unbounded::<()>();
    // 预先放入10个令牌
    for _ in 0..10 {
        sender.send(()).await.unwrap();
    }

    loop {
        // 获取令牌,无令牌时阻塞
        receiver.recv().await.unwrap();
        // 执行业务逻辑
        println!("处理任务");
    }
}

需要动态添加令牌时,调用sender.send(()).await即可。

2. 改造tokio::sync::Semaphore

虽然信号量默认是可复用的,但可以通过不归还许可实现消耗式逻辑:

use tokio::sync::Semaphore;

#[tokio::main]
async fn main() {
    let semaphore = Semaphore::new(10);

    loop {
        // 获取许可后不主动释放(不丢弃`_permit`)
        let _permit = semaphore.acquire().await.unwrap();
        // 执行业务逻辑
        println!("处理任务");
    }
}

许可会随着获取被永久消耗,可通过semaphore.add_permits(n)动态补充。

3. 专用令牌池库ticketed

这个 crate 专为一次性令牌池设计,API 更贴合你的需求:

use ticketed::TicketPool;

#[tokio::main]
async fn main() {
    let pool = TicketPool::new(10);

    loop {
        let _ticket = pool.acquire().await;
        // 执行业务逻辑
        println!("处理任务");
    }
}

支持pool.add_tickets(n)动态添加令牌,获取操作会自动阻塞直到有可用令牌。

内容的提问来源于stack exchange,提问作者eof

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 00:26:08