Skip to content
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

TinyTemplate object not thread safe? How to synchronize? #30

Open
KonradHoeffner opened this issue Jul 5, 2022 · 4 comments
Open

TinyTemplate object not thread safe? How to synchronize? #30

KonradHoeffner opened this issue Jul 5, 2022 · 4 comments

Comments

@KonradHoeffner
Copy link

KonradHoeffner commented Jul 5, 2022

I want to use TinyTemplate for an Actix Web application, but I run into problems making my TinyTemplate object lazy_static because it does not have the Sync trait. Is it possible to add that or is there a technical reason for that? I could understand that a mutable TinyTemplate object could add a template while another thread calls the render function but why can't two threads use the render function at the same time when they have non-mut reference? Is it recommended to just recreate a new TinyTemplate object every time render() is used or is it faster to reuse the same object and add some synchronization code? Or should I clone the object once for each CPU core and use some kind of pool? Is it possible to share a pointer to just the render() function and use that in a thread safe manner?
Sorry if those are basic questions, I'm still new to Rust, but TinyTemplate works very well for my use case but right now I recreate the TinyTemplate every time I need it and wonder if I'm doing it wrong.

@bheisler
Copy link
Owner

bheisler commented Jul 6, 2022

Hello! Thanks for the suggestion.

The honest answer is it never really occurred to me that anyone would want to do that. Unfortunately, now I've painted myself into a corner and can't fix this without a breaking change. The issue is that the formatter functions aren't required to implement Send or Sync - someone could configure a formatter that uses mutable state behind the scenes, if they wanted - and now Rust can't prove that it's safe to send those formatter functions (and therefore, the TinyTemplate object that contains them) between threads, so you can't. It's very unlikely that anyone is doing that, of course, but it's technically allowed and disallowing it would be a breaking change.

In the meantime until I fix it, yeah, you'll basically have to clone it for each thread.

@KonradHoeffner
Copy link
Author

Thanks for the detailed explanations! I didn't even know that Send or Sync are defined at the function level or that functions are allowed to change internal state when called from a non mutable reference, I will read those chapters of the Rust book.

a few hours later

I have now read about Send and Sync and that mutability is inherited but now I am more confused than before. Apparently, mutability is inherited in Rust and thus if I have a non mutable reference to something, I can't call methods that change the internal state. I guess that is a general problem I have with understanding Rust and I need to read more about it.

@bheisler
Copy link
Owner

Send and Sync are sort of strange. They're magical traits that are automatically derived by the compiler if it's safe to do so. They are, so far as I know, the only two such automatic traits. They aren't really a function-level thing, they're more a property of a type. The details aren't precisely relevant to this case, but the short version is that because I didn't specify Send or Sync on the bounds for the generic function type, the type-checker has to assume that they won't implement Send or Sync. Therefore, because it contains things that don't implement Send or Sync, the compiler can't automatically derive those traits for the TinyTemplate type.

@johnbartholomew
Copy link

It's kinda ugly, but to avoid the breaking change on the API it's also possible to export a separate TinyTemplate type that is Send+Sync. I tried this out in a fork:

master...johnbartholomew:TinyTemplate:sync

It adds a module sync which just provides a Send+Sync version of TinyTemplate, so that the existing exported type remains unchanged. Maybe with some massaging the code size could be reduced a little, there's obviously redundancy in the implementation since it's two types that are almost the same.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants