The Threadpool
The threadpool is where we'll process the CPU intensive tasks and the I/O tasks
which can't be reasonably handled by epoll, kqueue or IOCP
. One of these tasks
are file system operations.
The reason for doing file I/O in the thread pool is complex, but the main takeaway
is that due to how files are cached and how the hard drive works, most often the
file I/O will be Ready
almost immediately, so waiting for that in a event queue
has very little effect in practice.
The second reason is that while Windows do have a completion based model, Linux and macOS doesn't. Reading a file into a buffer which your process controls can take some time, and if we do that in our main loop it will block a little bit which we really try to avoid.
By doing this in a thread pool we make sure that these operations won't block our main event loop and only notify us once the data is ready for us in memory.
The code we need to add to process events from the thread pool is short an simple:
fn process_threadpool_events(&mut self, thread_id: usize, callback_id: usize, data: Js {
self.callbacks_to_run.push((callback_id, data));
self.available_threads.push(thread_id);
}
We take thread_id
, callback_id
and data
as arguments. We get this through
the channel we have shared with our threadpool
threads.
Once we have that information we push our callbacks into the queue of callbacks_to_run
which will run on the next call to run_callbacks
we went through in the previous chapter.
Last we take the id
of the thread that sent the finished task and put it into
our pool of available threads.