Reviewed on: 2022-03-22
The input pipeline library is single-threaded. More precisely:
input_handler::InputHandler::handle_input_event() is not Send.
input_pipeline::InputPipelineAssembly is not Send. This is because
handle_input_event() is not Send, which means thatTasks created to run handle_input_event() futures are not Send, which means thatVec of Tasks in InputPipeline is not Send, which means thatInputPipelineAssembly is not Send.input_pipeline::InputPipeline is not Send. This is analogous to the argument for InputPipelineAssembly.
Meeting the Send requirement is hard.
quiche@ forgets the exact details, but remembers that meeting Send was one of the blockers to landing FactoryResetHandler.
Running on a SendExecutor makes it harder to reason about correctness.
With a SendExecutor, a Future may be preempted to run another Future that accesses the same data. Or another thread may access the same data simultaneously.
While the Rust compiler will verify that these calls are memory-safe, the code may still have deadlocks, or semantic errors.
For example:
The deadlock and semantic error risks aren‘t unique to SendExecutors, but they’re harder to check for with SendExecutors. This is because, with a SendExecutor the data access from the other Future might occur at any moment (outside of critical regions, of course).
In contrast, with a LocalExecutor, a Future will run until it yields (by invoking the await operator). This greatly reduces the locations (line of code) where the program might have conflicting actions by multiple Futures accessing the same data.
It's unlikely that multithreading would improve input pipeline performance (and might make it worse).
InputHandlers don't do a lot of computation, and all of their I/O is asynchronous. This limits the speed-up that we might get from executing handlers in parallel.
On the other hand, multithreading introduces costs:
Arc instead of Rc, and Mutex instead of RefCell) requires synchronization between processors.Multithreading makes programs a greater risk to system health.
When a single threaded program gets stuck in an infinite loop, it can only consume a single core. A multi-threaded program can consume multiple cores.