There are several fucntions/ structs in the app that will use the object aws_utils so to me it makes sense to create a static variable of it during the server startup and keep using this variable every time i need aws_utils object. So i created it as follows
I think there's not much reason for using lazy_static because once_cell::sync::Lazy has the same functionality without requiring a macro. Given that once_cell is also more general, and that its API is being considered for inclusion in std, it is probably the unambiguously better choice.
I'm particularly curious about OnceBox. This doesn't seem to be implementable using atomics without unsafe. Should OnceBox be considered faster than once_cell::sync::OnceCell? Are there some downsides to it, except for the possibility of executing the initialization code more than once?
I'm not sure. However, when shared-memory concurrency is being used, I find it almost completely useless to talk about this kind of micro-optimization. Unless you are using shared-memory concurrency in a way that it should not be used in a modern programming style (i.e., heavy contention), the cost of locks and atomics is almost always trivial.
Some anecdata for context: in a simple experiment I performed a couple of months ago, I was trying to find out whether a custom SQLite wrapper I was writing could have benefited from a single-threaded unsafe usage scheme. This would have allowed me to turn off mutexes in the library (as well as in the FFI-wrapping code) completely. I was unable to measure any meaningful difference between mutex-protected and unprotected access to the library when contention did not occur; so much so that even a trivial in-memory query (like select foo from bar limit 1) dominated the time spent in locking.
If I understand right, then neither OnceCell nor OnceBox use locking after the cell/box is initialized. They both seem to do an acquire load first, and if that load indicates that the cell is initialized, there will be no locking involved (also in case of OnceCell). So I guess OnceBox doesn't really have a huge advantage over OnceCell. Maybe extracting the value is a bit faster with OnceBox, but like you said it's probably barely noticable. Perhaps on embedded devices, code (program/binary) size might be smaller for OnceBox.