Search code examples
multithreadingperformancerustautomatic-ref-counting

Rust struct field as arc vs. struct as arc


I have a question regarding the Arc in Rust. I want to do something with multi-threading and stumbled on Arcs to give multiple threads access to the same data. At the moment, I use a struct with the fields being Arcs, and the struct is just normal. I use the struct as some kind of configuration and give the function that needs it a clone to the needed field. My question is, would it be better practice to make the struct variable an arc and the fields normal than give it to the function and retrieve the needed fields? I'm very interested in the memory usage and speed differences; are there any, or is it just convenience to use one or the other?

Code I think of:

struct Config{
   name: String,
   id:   u32,
   ...
}

let myconf = Arc::new(Config::default());

do_stuff(myconf.clone()).await;
...

current code:

struct Config{
   name: Arc<String>,
   id:   Arc<u32>,
   ...
}

let myconf = Config::default();
do_stuff(myconf.name.clone(), myconf.id.clone()).await;
...

Solution

  • If all fields are Arc, it is usually better to hold the entire struct behind an Arc instead of just many Arcs for each field.

    This way, cloning and drops are cheaper (just one reference count bump instead of many), moving the struct around is cheaper (just one pointer instead of many), struct creation is faster (one allocation instead of many), less memory is used (because each Arc requires two additional words for the reference count), and cache locality is better (since the data is in contiguous allocation instead of scattered in many), and there is also less pointer chasing.

    If you want to hide the fact that an Arc is used from the interface, you can have two structs, Config and ConfigInner, and let Config be just a wrapper around Arc<ConfigInner>.