Search code examples
performanceruststatic-variableslazy-static

What is better in Rust: defining a static variable to access it globally or passing a non-static variable through function arguments?


If a variable is used in multiple functions in a file, is it better to define it as static rather than passing a non-static variable through function arguments? Does this have a performance impact?

An example using a static variable:

lazy_static! {
    static ref FOO: Foo = {
        Foo::new()
    };
}

fn main() {
    do_foo();
    do_another_foo();
}

fn do_foo() {
    FOO.bar();
    // ...
}

fn do_another_foo() {
    let name = FOO.name();
    // ...
}

An example using a normal variable:

fn main() {
    let foo = Foo::new();
    do_foo(&foo);
    do_another_foo(&foo);
}

fn do_foo(foo: &Foo) {
    foo.bar();
    // ...
}

fn do_another_foo(foo: &Foo) {
    let name = foo.name();
    // ...
}

Solution

  • If you are using lazy_static!, there is quite a bit of overhead every time the variable is accessed. As the name suggests, lazy_static! vars are initialized lazily (on demand). That means every time one attempts to read the static variable, there is a check to make sure the variable is initialized or initialize it accordingly.

    lazy_static! would probably be a lot slower than passing the variable through function argument.

    There are also the const and static keywords. In the case of the const keyword, the value is inlined where the const is used (think #define in C++). In the case of the static keyword, there is only 1 instance of the variable that is inlined in the binary. Referencing the static variable would be like a pointer to part of the binary.

    Both of these options would be faster than using lazy_static! when possible.

    Also, with compiler optimizations, functions are likely to be inlined. The compiler can then optimize away the argument passing. Then there wouldn't be any overhead for passing arguments at all.

    I would guess that function arguments are about on par with const/static.

    That said, generally prefer passing state through function arguments rather than using global state. Global state tends to lead towards messy code and thus poor performance.