Module: Dotsync::Parallel
- Defined in:
- lib/dotsync/utils/parallel.rb
Overview
Thread-based parallel execution for independent operations.
Why Parallelization?
Dotsync processes multiple independent mappings (e.g., nvim, alacritty, zsh configs). Each mapping's diff computation and file transfer is independent of others. By processing mappings in parallel, we utilize multiple CPU cores and overlap I/O waits.
Implementation Details
Uses Ruby's native Thread class with a work-stealing queue pattern:
- Pre-sized results array for thread-safe index assignment (no mutex needed for writes)
- Queue-based work distribution for automatic load balancing
- Errors collected and re-raised after all threads complete
When It Helps
Parallelization provides the most benefit when:
- Processing many mappings (5+ independent directories)
- Mappings have similar sizes (good load distribution)
- I/O-bound operations (file reads/writes overlap)
For small mapping counts or CPU-bound work, the thread overhead may negate benefits.
Constant Summary collapse
- DEFAULT_THREADS =
Default number of threads (matches typical CPU core count)
4
Class Method Summary collapse
-
.each(items, threads: DEFAULT_THREADS) {|item| ... } ⇒ Object
Executes a block for each item in parallel, ignoring return values.
-
.map(items, threads: DEFAULT_THREADS) {|item| ... } ⇒ Array
Executes a block for each item in the collection using parallel threads.
Class Method Details
.each(items, threads: DEFAULT_THREADS) {|item| ... } ⇒ Object
Executes a block for each item in parallel, ignoring return values. Useful for side-effect operations like file transfers.
89 90 91 92 |
# File 'lib/dotsync/utils/parallel.rb', line 89 def self.each(items, threads: DEFAULT_THREADS, &block) map(items, threads: threads, &block) nil end |
.map(items, threads: DEFAULT_THREADS) {|item| ... } ⇒ Array
Executes a block for each item in the collection using parallel threads. Returns results in the same order as the input collection.
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/dotsync/utils/parallel.rb', line 44 def self.map(items, threads: DEFAULT_THREADS, &block) return [] if items.empty? return items.map(&block) if items.size == 1 # Limit threads to item count thread_count = [threads, items.size].min # Create indexed work items work_queue = Queue.new items.each_with_index { |item, idx| work_queue << [idx, item] } # Results array (pre-sized for thread safety with index assignment) results = Array.new(items.size) mutex = Mutex.new errors = [] # Spawn worker threads workers = thread_count.times.map do Thread.new do loop do idx, item = work_queue.pop(true) rescue break begin results[idx] = yield(item) rescue => e mutex.synchronize { errors << e } end end end end # Wait for completion workers.each(&:join) # Re-raise first error if any occurred raise errors.first unless errors.empty? results end |