4 ms·
I've written some threaded ruby code in the past and in addition to what was said in this article I would like to emphasize 2 more points: 1. Every time you ha
by _odey 4y ago
I've written some threaded ruby code in the past and in addition to what was said in this article I would like to emphasize 2 more points:
1. Every time you have a shared data structure, put a Mutex around it's usage (even in POC examples so people learn the properly). In the reproduction example line 4 you have `ids = Set.new` (the shared data structure) and on line 9 `ids << semaphores['test'].object_id`, since this is within a thread you need to put a Mutex around the push to `ids`. You can still have `semaphores['test'].object_id` outside the Mutex, assigning that to a variable and then push that to `ids` in the synchronize block to achieve the same result. If you have both inside the Mutex it would hide the presented issue.
2. Write stress tests that loop through your multithreaded code multiple times with trivial workloads; 100 times might not be enough to trigger a concurrency issue, you might need tens of thousands, or millions of iterations, or more. So don't be afraid to have the loop size configurable and just run it for a longer period of time, just to make sure. In CI you can tweak the loop size to have it running for let's say 3-5 minutes. That should make it relevant and still keep it fast/cheap enough.
Additionally, ruby now has Ractors, but still marked as experimental. These are amazing as you not only get safe parallelism (not just concurrency, true parallelism), but also data safety as a piece of data is either copied deeply, or ownership is passed to one single Ractor. Fingers crossed we see it stable soon.