Replies: 14 comments 27 replies
-
Impact on
|
Beta Was this translation helpful? Give feedback.
-
Broader ImpactOutside of The event loop being blocked while we're running the app schedule causes a bunch of problems:
For a quick rundown on where input events come from (in general):
However, if Also, while Footnotes
|
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
(reserved in case I missed any) |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
Thread-Local ExecutorThis is my main proposal for decoupling
On most targets, we can then move the world(s) off the main thread upfront and proxy any "must run on the ___ thread" operations through an executor. Rather than force the entire system onto the main thread, we can just scope the parts that borrow A system that looks like this: // This system can only run on the main thread.
fn foo(mut x: ResMut<X>, y: NonSend<Y>) {
*x.field = y.func();
} Would be rewritten like this: // This system can run on any thread.
fn foo(mut x: ResMut<X>, main_thread: Res<ThreadLocal<Main>>) {
// Only this closure runs on the main thread.
*x.field = main_thread.run(|tls: &mut NonSendResources| {
let y = tls.get::<Y>();
y.func()
});
} Or, if we preserve more of the existing ergonomics by adding a // This system can run on any thread.
fn foo(mut x: ResMut<X>, main_thread: Res<ThreadLocal<Main>>) {
// Only this closure runs on the main thread.
*x.field = main_thread.run(|y: &Y| y.func());
} TODO: Show example app runner. Change DetectionIf
|
Beta Was this translation helpful? Give feedback.
-
Bring your own event loopIf you're writing a plugin that spawns its own dedicated thread, then unless something is specifically tied to the main thread, you can avoid The suggested |
Beta Was this translation helpful? Give feedback.
-
TODO: |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
Use a thread local abstraction and change NonSend to be a marker to run on main threadWe can use a lib like https://docs.rs/thread-local-object/latest/thread_local_object/ to keep storing the NonSend reources in World. Then we just make NonSend something that tells the system to run on the main thread. fn my_system(non_send_res: NonSend<Res<ThreadLocal<MyResource>>>) {
non_send_res.get(| resource | {
// do something with the resource.
});
}
// this could potentially work with components too
fn my_query_system(non_send_q: NonSend<Query<ThreadLocal<MyComponent>>> {
for my_component in &non_send_q {
my_component.get(| my_c | {
// do something with the component
});
}
} There are at least a couple disadvantages to this approach. The lib above doesn't drop the contained value when the ThreadLocal is dropped. Only when the thread is exited. Also this keeps the complexity of scheduling resources in the scheduler rather than moving it out of it like the above recommended method. The advantages are that it keeps the values "owned" by the world and can even work for NonSend Components. edit: Another disadvatage is that the lib I'm using only allows for usize number of ThreadLocal instances ever existing. This is especially a problem because it doesn't reuse it's internal index. i.e. dropping a resource would not free it's index. This could probably be worked around by rolling our own solution though. |
Beta Was this translation helpful? Give feedback.
-
I was looking at the Pros:
Cons:
Possible extensions include:
|
Beta Was this translation helpful? Give feedback.
-
Summary
The
World
would be a betterplacetype if thread-local data was kept out of it.World
owning!Send
data forces us to block the main thread for long periods of time, which prevents useful concurrency. We can resolve this by storing!Send
data separately and exposing aSend
proxy for systems to send work to the main thread.Key Terms
winit
event polling loopBeta Was this translation helpful? Give feedback.
All reactions