Tokio OnceCell init function is called more than once

Version

└── tokio v1.16.1
    └── tokio-macros v1.7.0 (proc-macro)

Platform

Linux username 5.16.8-arch1-1 #1 SMP PREEMPT Tue, 08 Feb 2022 21:21:08 +0000 x86_64 GNU/Linux

Description

OnceCell init function is called more than once when a timeout occurs and tokio::spawn is done.

I tried this code:

use tokio::sync::OnceCell;
use std::time::Duration;

async fn some_computation() -> u32 {
    println!("once computation");
    tokio::time::sleep(Duration::from_secs(5)).await;
    1 + 1
}

static ONCE: OnceCell<u32> = OnceCell::const_new();

async fn read() {
        let result = ONCE.get_or_init(some_computation).await;
}

#[tokio::main]
async fn main() {
    for _ in 0..100 {
        tokio::spawn(async move {
            tokio::time::timeout(Duration::from_secs(1), read()).await;
        });
    }
    tokio::time::sleep(Duration::from_secs(10)).await;
}
[dependencies]
tokio = {version = "1", features = ["full"]}

I expected to see this happen:

The once computation should be printed only once.

Instead, this happened:

The once computation was printed more than once (6 times in my test)

Link of issue: OnceCell init function is called more than once · Issue #4496 · tokio-rs/tokio · GitHub

Is it okay?

If you abort the initialization operation before it produces a value, then it doesn't get initialized and will let another call make an attempt to initialize it.

1 Like

This is documented at OnceCell in tokio::sync - Rust.

If the provided operation is cancelled or panics, the initialization attempt is cancelled. If there are other tasks waiting for the value to be initialized, one of them will start another attempt at initializing the value.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.