Thread locals are often slower than they need to be. For example, if we have:
thread_local! {
static FOO: i32 = 777;
}
Every access of the form FOO.with(|foo| ...) will first check whether FOO is initialized, and then initialize it if this is the first access. On some (most?) platforms we can statically initialize thread locals with a constant expression (in this case the constant expression is 777).
A check on every access can be fairly costly, and we should try to avoid checks whenever possible. It is possible to avoid them by using #[thread_local] instead of thread_local!, but that is an unstable feature without a clear stabilization plan...
In #17954 @alexcrichton said:
I do not think we should strive to stabilize #[thread_local]. It's incredibly not portable which makes it not too useful for most software. We should strive to improve thread_local!. The feature to implement is for the compiler to understand whether the initialization expression is a constant expression or not. If it's a constant expression then we can bypass the None storage and "am I initialized checks", making it equivalent to raw #[thread_local]
@eddyb answered:
That's easy in the compiler but thread_local! is not implemented in the compiler.
@arielb1 suggests:
... But we could add an eager_thread_local! macro for that case.
@alexcrichton adds:
As for how to implement a "const expr detection" in a macro I'm not entirely sure. We could either move the implementation into the compiler (which I'd prefer to avoid) or take @arielb1's suggestion of a new macro or a variant of the current macro's syntax.
For example we could "perverse" the meaning via: thread_local!(const A: i32 = 3); where static in the macro means "lazily initialized, but any expression valid" and const means "must be a constant expression". I don't think this is a good idea, but an example of what we might do.
My question after all that would be:
Can we perhaps make the thread_local! macro expand to a special lang item that provides two implementations - one for the lazy initialization case and one for the static initialization zero-checks case? Then the compiler would choose one of them, depending on whether the initialization expression is a constant expression.
Thread locals are often slower than they need to be. For example, if we have:
Every access of the form
FOO.with(|foo| ...)will first check whetherFOOis initialized, and then initialize it if this is the first access. On some (most?) platforms we can statically initialize thread locals with a constant expression (in this case the constant expression is777).A check on every access can be fairly costly, and we should try to avoid checks whenever possible. It is possible to avoid them by using
#[thread_local]instead ofthread_local!, but that is an unstable feature without a clear stabilization plan...In #17954 @alexcrichton said:
@eddyb answered:
@arielb1 suggests:
@alexcrichton adds:
My question after all that would be:
Can we perhaps make the
thread_local!macro expand to a special lang item that provides two implementations - one for the lazy initialization case and one for the static initialization zero-checks case? Then the compiler would choose one of them, depending on whether the initialization expression is a constant expression.