Skip to content

Use once_cell instead of lazy_static #416

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
1 commit merged into from
Oct 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ crossbeam-utils = "0.6.6"
futures-core-preview = "=0.3.0-alpha.19"
futures-io-preview = "=0.3.0-alpha.19"
futures-timer = "1.0.2"
lazy_static = "1.4.0"
log = { version = "0.4.8", features = ["kv_unstable"] }
memchr = "2.2.1"
mio = "0.6.19"
mio-uds = "0.6.7"
num_cpus = "1.10.1"
once_cell = "1.2.0"
pin-utils = "0.1.0-alpha.4"
slab = "0.4.2"
kv-log-macro = "1.0.4"
Expand Down
34 changes: 16 additions & 18 deletions src/net/driver/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::fmt;
use std::sync::{Arc, Mutex};

use lazy_static::lazy_static;
use mio::{self, Evented};
use once_cell::sync::Lazy;
use slab::Slab;

use crate::io;
Expand Down Expand Up @@ -100,25 +100,23 @@ impl Reactor {
// }
}

lazy_static! {
/// The state of the global networking driver.
static ref REACTOR: Reactor = {
// Spawn a thread that waits on the poller for new events and wakes up tasks blocked on I/O
// handles.
std::thread::Builder::new()
.name("async-net-driver".to_string())
.spawn(move || {
// If the driver thread panics, there's not much we can do. It is not a
// recoverable error and there is no place to propagate it into so we just abort.
abort_on_panic(|| {
main_loop().expect("async networking thread has panicked");
})
/// The state of the global networking driver.
static REACTOR: Lazy<Reactor> = Lazy::new(|| {
// Spawn a thread that waits on the poller for new events and wakes up tasks blocked on I/O
// handles.
std::thread::Builder::new()
.name("async-net-driver".to_string())
.spawn(move || {
// If the driver thread panics, there's not much we can do. It is not a
// recoverable error and there is no place to propagate it into so we just abort.
abort_on_panic(|| {
main_loop().expect("async networking thread has panicked");
})
.expect("cannot start a thread driving blocking tasks");
})
.expect("cannot start a thread driving blocking tasks");

Reactor::new().expect("cannot initialize reactor")
};
}
Reactor::new().expect("cannot initialize reactor")
});

/// Waits on the poller for new events and wakes up tasks blocked on I/O handles.
fn main_loop() -> io::Result<()> {
Expand Down
44 changes: 22 additions & 22 deletions src/task/blocking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::thread;
use std::time::Duration;

use crossbeam_channel::{bounded, Receiver, Sender};
use lazy_static::lazy_static;
use once_cell::sync::Lazy;

use crate::task::task::{JoinHandle, Tag};
use crate::utils::abort_on_panic;
Expand All @@ -19,30 +19,30 @@ struct Pool {
receiver: Receiver<async_task::Task<Tag>>,
}

lazy_static! {
static ref POOL: Pool = {
for _ in 0..2 {
thread::Builder::new()
.name("async-blocking-driver".to_string())
.spawn(|| abort_on_panic(|| {
static POOL: Lazy<Pool> = Lazy::new(|| {
for _ in 0..2 {
thread::Builder::new()
.name("async-blocking-driver".to_string())
.spawn(|| {
abort_on_panic(|| {
for task in &POOL.receiver {
task.run();
}
}))
.expect("cannot start a thread driving blocking tasks");
}

// We want to use an unbuffered channel here to help
// us drive our dynamic control. In effect, the
// kernel's scheduler becomes the queue, reducing
// the number of buffers that work must flow through
// before being acted on by a core. This helps keep
// latency snappy in the overall async system by
// reducing bufferbloat.
let (sender, receiver) = bounded(0);
Pool { sender, receiver }
};
}
})
})
.expect("cannot start a thread driving blocking tasks");
}

// We want to use an unbuffered channel here to help
// us drive our dynamic control. In effect, the
// kernel's scheduler becomes the queue, reducing
// the number of buffers that work must flow through
// before being acted on by a core. This helps keep
// latency snappy in the overall async system by
// reducing bufferbloat.
let (sender, receiver) = bounded(0);
Pool { sender, receiver }
});

// Create up to MAX_THREADS dynamic blocking task worker threads.
// Dynamic threads will terminate themselves if they don't
Expand Down
40 changes: 19 additions & 21 deletions src/task/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::thread;

use crossbeam_deque::{Injector, Stealer, Worker};
use kv_log_macro::trace;
use lazy_static::lazy_static;
use once_cell::sync::Lazy;

use super::sleepers::Sleepers;
use super::task;
Expand Down Expand Up @@ -111,28 +111,26 @@ impl Pool {

#[inline]
pub(crate) fn get() -> &'static Pool {
lazy_static! {
static ref POOL: Pool = {
let num_threads = num_cpus::get().max(1);
let mut stealers = Vec::new();
static POOL: Lazy<Pool> = Lazy::new(|| {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this doesn't really make heavy use of Deref for Lazy, a more minimal and direct approach would be to use OnceCell.

static POOL: OnceCell<Pool> = OnceCell::new();
POOL.get_or_init(|| ...)

But, as we are using Lazy elsewhere, I guess it's better to use it here as well, just for consistency

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I make use of Lazy mostly to streamline with on-going rust RFC. I think this will be easier for later maintenance.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The RFC proposes both OnceCell and Lazy, as OnceCell is strictly more powerful.

let num_threads = num_cpus::get().max(1);
let mut stealers = Vec::new();

// Spawn worker threads.
for _ in 0..num_threads {
let worker = Worker::new_fifo();
stealers.push(worker.stealer());
// Spawn worker threads.
for _ in 0..num_threads {
let worker = Worker::new_fifo();
stealers.push(worker.stealer());

thread::Builder::new()
.name("async-task-driver".to_string())
.spawn(|| abort_on_panic(|| worker::main_loop(worker)))
.expect("cannot start a thread driving tasks");
}
thread::Builder::new()
.name("async-task-driver".to_string())
.spawn(|| abort_on_panic(|| worker::main_loop(worker)))
.expect("cannot start a thread driving tasks");
}

Pool {
injector: Injector::new(),
stealers,
sleepers: Sleepers::new(),
}
};
}
Pool {
injector: Injector::new(),
stealers,
sleepers: Sleepers::new(),
}
});
&*POOL
}
6 changes: 2 additions & 4 deletions src/task/task_local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::future::Future;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Mutex;

use lazy_static::lazy_static;
use once_cell::sync::Lazy;

use super::worker;
use crate::utils::abort_on_panic;
Expand Down Expand Up @@ -174,9 +174,7 @@ impl<T: Send + 'static> LocalKey<T> {
fn key(&self) -> usize {
#[cold]
fn init(key: &AtomicUsize) -> usize {
lazy_static! {
static ref COUNTER: Mutex<usize> = Mutex::new(1);
}
static COUNTER: Lazy<Mutex<usize>> = Lazy::new(|| Mutex::new(1));

let mut counter = COUNTER.lock().unwrap();
let prev = key.compare_and_swap(0, *counter, Ordering::AcqRel);
Expand Down