once_cell / LazyLock & dashmap
LazyLock (stdlib desde Rust 1.80) inicializa globais na primeira vez que são acessados. dashmap é um HashMap concorrente para caches e registros sem um mutex global.
Receita
use std::sync::LazyLock;
static CONFIG: LazyLock<String> = LazyLock::new(|| {
std::env::var("APP_NAME").unwrap_or_else(|_| "app".into())
});dashmap = "6"use dashmap::DashMap;
use std::sync::Arc;
fn main() {
let cache: Arc<DashMap<String, u64>> = Arc::new(DashMap::new());
cache.insert("user:1".into(), 42);
assert_eq!(*cache.get("user:1").unwrap(), 42);
}Quando usar isso:
- Clientes HTTP para todo o processo, conjuntos de regex, snapshots de configuração
- Tabelas de limite de taxa ou de sessão em memória (com política de expiração)
- Registro de serviços nomeados em daemons de longa duração
Exemplo de Trabalho
use std::sync::LazyLock;
use dashmap::DashMap;
static METRICS: LazyLock<DashMap<&'static str, u64>> =
LazyLock::new(DashMap::new);
fn inc(name: &'static str) {
*METRICS.entry(name).or_insert(0) += 1;
}
fn main() {
inc("requests");
inc("requests");
assert_eq!(*METRICS.get("requests").unwrap(), 2);
}O que isso demonstra:
LazyLocksubstituionce_cell::sync::Lazypara código novoDashMappermiteinsert/getconcorrentes- Prefira
Arc<DashMap>no estado do Axum para testabilidade
Mergulho Profundo
LazyLock vs once_cell
| Ferramenta | Status |
|---|---|
std::sync::LazyLock | Preferido em Rust 1.80+ |
once_cell | Ainda usado em crates MSRV mais antigos |
tokio::sync::OnceCell | Inicialização assíncrona |
DashMap vs RwLock<HashMap>
DashMap fragmenta os locks internamente; melhor para muitos leitores/escritores em chaves independentes. Pontos de acesso de chave única ainda causam contenção.
Armadilhas
- Estático mutável sem sincronização - erro de compilação ou UB. Correção:
LazyLock,Mutex, ouDashMap. - DashMap como armazenamento autoritativo - dados perdidos na reinicialização. Correção: persista em um banco de dados; apenas cache.
- Crescimento ilimitado do cache - OOM (Out Of Memory). Correção: TTL, camada LRU, ou crate
moka. - Pânico do LazyLock na inicialização - falha no primeiro acesso. Correção: retorne
Resultda configuração interna ou useOnceLock<Result<T>>. - Iterar sobre DashMap durante a mutação - deadlocks possíveis. Correção: capture as chaves primeiro.
Alternativas
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
RwLock<HashMap> | Baixa contenção | Muitas chaves concorrentes |
moka / cached | Caches TTL | Contadores simples |
tokio::sync::Mutex<HashMap> | Apenas lock único assíncrono | Alta concorrência de leitura |
FAQs
Ainda preciso de once_cell em 1.97?
Raramente para LazyLock. once_cell permanece para crates do ecossistema ainda não migrados.
DashMap e Tokio?
A API síncrona é aceitável para seções críticas curtas; evite esperas longas enquanto segura os locks fragmentados.
Testando globais?
Prefira injetar Arc<DashMap> através do estado do aplicativo em vez de estáticos em testes.
LazyLock e MSRV?
Rust 1.97 inclui LazyLock. Documente o MSRV se estiver suportando compiladores mais antigos com once_cell.
Relacionado
- Arc para estado compartilhado
- Mutex e RwLock
- Estado compartilhado em async
- Melhores Práticas de Crates Essenciais
Versões da Stack: Esta página foi escrita para Rust 1.97.0 (edição 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, e Polars 0.46+.