[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-7776":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":14,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":15,"stars7d":16,"stars30d":17,"stars90d":15,"forks30d":15,"starsTrendScore":16,"compositeScore":18,"rankGlobal":9,"rankLanguage":9,"license":19,"archived":20,"fork":20,"defaultBranch":21,"hasWiki":22,"hasPages":20,"topics":23,"createdAt":9,"pushedAt":9,"updatedAt":24,"readmeContent":25,"aiSummary":26,"trendingCount":15,"starSnapshotCount":15,"syncStatus":27,"lastSyncTime":28,"discoverSource":29},7776,"parallel","grosser\u002Fparallel","grosser","Ruby: parallel processing made simple and fast",null,"Ruby",4260,262,71,35,0,1,14,61.16,"MIT License",false,"master",true,[],"2026-06-12 04:00:35","Parallel\n==============\n[![Gem Version](https:\u002F\u002Fbadge.fury.io\u002Frb\u002Fparallel.svg)](https:\u002F\u002Frubygems.org\u002Fgems\u002Fparallel)\n[![Build Status](https:\u002F\u002Fgithub.com\u002Fgrosser\u002Fparallel\u002Factions\u002Fworkflows\u002Factions.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fgrosser\u002Fparallel\u002Factions\u002Fworkflows\u002Factions.yml)\n\n\nRun any code in parallel Processes(> use all CPUs), Threads(> speedup blocking operations), or Ractors(> use all CPUs).\u003Cbr\u002F>\nBest suited for map-reduce or e.g. parallel downloads\u002Fuploads.\n\nInstall\n=======\n\n```Bash\ngem install parallel\n```\n\nUsage\n=====\n\n```Ruby\n# 2 CPUs -> work in 2 processes (a,b + c)\nresults = Parallel.map(['a','b','c']) do |one_letter|\n  SomeClass.expensive_calculation(one_letter)\nend\n\n# 3 Processes -> finished after 1 run\nresults = Parallel.map(['a','b','c'], in_processes: 3) { |one_letter| SomeClass.expensive_calculation(one_letter) }\n\n# 3 Threads -> finished after 1 run\nresults = Parallel.map(['a','b','c'], in_threads: 3) { |one_letter| SomeClass.expensive_calculation(one_letter) }\n\n# 3 Ractors -> finished after 1 run\nresults = Parallel.map(['a','b','c'], in_ractors: 3, ractor: [SomeClass, :expensive_calculation])\n```\n\nSame can be done with `each`\n```Ruby\nParallel.each(['a','b','c']) { |one_letter| ... }\n```\nor `each_with_index`, `map_with_index`, `flat_map`\n\nProduce one item at a time with `lambda` (anything that responds to `.call`) or `Queue`.\n\n```Ruby\nitems = [1,2,3]\nParallel.each( -> { items.pop || Parallel::Stop }) { |number| ... }\n```\n\nAlso supports `any?` or `all?`\n\n```Ruby\nParallel.any?([1,2,3,4,5,6,7]) { |number| number == 4 }\n# => true\n\nParallel.all?([1,2,nil,4,5]) { |number| number != nil }\n# => false\n```\n\nProcesses\u002FThreads are workers, they grab the next piece of work when they finish.\n\n### Processes\n - Speedup through multiple CPUs\n - Speedup for blocking operations\n - Variables are protected from change\n - Extra memory used\n - Child processes are killed when your main process is killed through Ctrl+c or kill -2\n\n### Threads\n - Speedup for blocking operations\n - Variables can be shared\u002Fmodified\n - No extra memory used\n\n### Ractors\n - Ruby 3.0+ only\n - Speedup for blocking operations\n - No extra memory used\n - Very fast to spawn\n - Experimental and unstable\n - `start` and `finish` hooks are called on main thread\n - Variables must be passed in `Parallel.map([1,2,3].map { |i| [i, ARGV, local_var] }, ...`\n - use `Ractor.make_shareable` to pass in global objects\n\n### ActiveRecord\n\n#### Connection Lost\n\n - Multithreading needs connection pooling, forks need reconnects\n - Adjust connection pool size in `config\u002Fdatabase.yml` when multithreading\n\n```Ruby\n# reproducibly fixes things (spec\u002Fcases\u002Fmap_with_ar.rb)\nParallel.each(User.all, in_processes: 8) do |user|\n  user.update_attribute(:some_attribute, some_value)\nend\nUser.connection.reconnect!\n\n# maybe helps: explicitly use connection pool\nParallel.each(User.all, in_threads: 8) do |user|\n  ActiveRecord::Base.connection_pool.with_connection do\n    user.update_attribute(:some_attribute, some_value)\n  end\nend\n\n# maybe helps: reconnect once inside every fork\nParallel.each(User.all, in_processes: 8) do |user|\n  @reconnected ||= User.connection.reconnect! || true\n  user.update_attribute(:some_attribute, some_value)\nend\n```\n\n#### NameError: uninitialized constant\n\nA race happens when ActiveRecord models are autoloaded inside parallel threads\nin environments that lazy-load, like development, test, or migrations.\n\nTo fix, autoload classes before the parallel block with either `require '\u003Cmodelname>'` or  `ModelName.class`.\n\n### Break\n\n```Ruby\nParallel.map([1, 2, 3]) do |i|\n  raise Parallel::Break # -> stops after all current items are finished\nend\n```\n\n```Ruby\nParallel.map([1, 2, 3]) { |i| raise Parallel::Break, i if i == 2 } == 2\n```\n\n### Kill\n\nOnly use if whatever is executing in the sub-command is safe to kill at any point\n\n```Ruby\nParallel.map([1,2,3]) do |x|\n  raise Parallel::Kill if x == 1# -> stop all sub-processes, killing them instantly\n  sleep 100 # Do stuff\nend\n```\n\n### Progress \u002F ETA\n\n```Ruby\n# gem install ruby-progressbar\n\nParallel.map(1..50, progress: \"Doing stuff\") { sleep 1 }\n\n# Doing stuff | ETA: 00:00:02 | ====================               | Time: 00:00:10\n```\n\nUse `:finish` or `:start` hook to get progress information.\n - `:start` has item and index\n - `:finish` has item, index, and result\n\nThey are called on the main process and protected with a mutex.\n(To just get the index, use the more performant `Parallel.each_with_index`)\n\n```Ruby\nParallel.map(1..100, finish: -> (item, i, result) { ... do something ... }) { sleep 1 }\n```\n\nSet `finish_in_order: true` to call the `:finish` hook in the order of the input (will take longer to see initial output).\n\n```Ruby\nParallel.map(1..9, finish: -> (item, i, result) { puts \"#{item} ok\" }, finish_in_order: true) { sleep rand }\n```\n\n### Worker number\n\nUse `Parallel.worker_number` to determine the worker slot in which your\ntask is running.\n\n```Ruby\nParallel.each(1..5, in_processes: 2) { |i| puts \"Item: #{i}, Worker: #{Parallel.worker_number}\" }\nItem: 1, Worker: 1\nItem: 2, Worker: 0\nItem: 3, Worker: 1\nItem: 4, Worker: 0\nItem: 5, Worker: 1\n```\n\n### Dynamically generating jobs\n\nExample: wait for work to arrive or sleep\n\n```ruby\nqueue = []\nThread.new { loop { queue \u003C\u003C rand(100); sleep 2 } } # job producer\nParallel.map(Proc.new { queue.pop }, in_processes: 3) { |f| f ? puts(\"#{f} received\") : sleep(1) }\n```\n\n### Processes vs Wire serializer: security risk for hardened environments\n\nWorker processes talk to the parent over an anonymous pipe using `Marshal` by default.\n\nIf you've hardened your host against `ptrace`\u002F`\u002Fproc\u002F\u003Cpid>\u002Fmem` access (e.g. `ptrace_scope >= 2`) and\nwant to also close the `\u002Fproc\u002F\u003Cpid>\u002Ffd\u002F\u003Cn>` pipe-reopen vector, use the HMAC serializer.\n\nIt length-prefixes and HMAC-SHA256 signs each message with a per-worker secret generated before `fork`,\nso a same-UID attacker that reopens the pipe can't inject a forged `Marshal` payload into the parent (which would be RCE).\n\nRaises `SecurityError` on mismatch (not a `StandardError`).\n\n```ruby\nParallel.map(items, in_processes: 2, serializer: Parallel::Serializer::Hmac.new) { ... }\n```\n\nTips\n====\n\n - [Benchmark\u002FTest] Disable threading\u002Fforking with `in_threads: 0` or `in_processes: 0`, to run the same code with different setups\n - [Isolation] Do not reuse previous worker processes: `isolation: true`\n - [Stop all processes with an alternate interrupt signal] `'INT'` (from `ctrl+c`) is caught by default. Catch `'TERM'` (from `kill`) with `interrupt_signal: 'TERM'`\n - [Process count via ENV] `PARALLEL_PROCESSOR_COUNT=16` will use `16` instead of the number of processors detected. This is used to reconfigure a tool using `parallel` without inserting custom logic.\n - [Process count] `parallel` uses a number of processors seen by the OS for process count by default. If you want to use a value considering CPU quota, please add `concurrent-ruby` to your `Gemfile`.\n\nTODO\n====\n - Replace Signal trapping with simple `rescue Interrupt` handler\n\nAuthors\n=======\n\n### [Contributors](https:\u002F\u002Fgithub.com\u002Fgrosser\u002Fparallel\u002Fgraphs\u002Fcontributors)\n - [Przemyslaw Wroblewski](https:\u002F\u002Fgithub.com\u002Flowang)\n - [TJ Holowaychuk](http:\u002F\u002Fvision-media.ca\u002F)\n - [Masatomo Nakano](https:\u002F\u002Fgithub.com\u002Fmasatomo)\n - [Fred Wu](http:\u002F\u002Ffredwu.me)\n - [mikezter](https:\u002F\u002Fgithub.com\u002Fmikezter)\n - [Jeremy Durham](http:\u002F\u002Fwww.jeremydurham.com)\n - [Nick Gauthier](http:\u002F\u002Fwww.ngauthier.com)\n - [Andrew Bowerman](http:\u002F\u002Fandrewbowerman.com)\n - [Byron Bowerman](http:\u002F\u002Fblog.bm5k.com\u002F)\n - [Mikko Kokkonen](https:\u002F\u002Fgithub.com\u002Fmikian)\n - [brian p o'rourke](https:\u002F\u002Fgithub.com\u002Fbpo)\n - [Norio Sato]\n - [Neal Stewart](https:\u002F\u002Fgithub.com\u002Fn-time)\n - [Jurriaan Pruis](https:\u002F\u002Fgithub.com\u002Fjurriaan)\n - [Rob Worley](https:\u002F\u002Fgithub.com\u002Frobworley)\n - [Tasveer Singh](https:\u002F\u002Fgithub.com\u002Ftazsingh)\n - [Joachim](https:\u002F\u002Fgithub.com\u002Fjmozmoz)\n - [yaoguai](https:\u002F\u002Fgithub.com\u002Fyaoguai)\n - [Bartosz Dziewoński](https:\u002F\u002Fgithub.com\u002FMatmaRex)\n - [yaoguai](https:\u002F\u002Fgithub.com\u002Fyaoguai)\n - [Guillaume Hain](https:\u002F\u002Fgithub.com\u002Fzedtux)\n - [Adam Wróbel](https:\u002F\u002Fgithub.com\u002Famw)\n - [Matthew Brennan](https:\u002F\u002Fgithub.com\u002Fmattyb)\n - [Brendan Dougherty](https:\u002F\u002Fgithub.com\u002Fbrendar)\n - [Daniel Finnie](https:\u002F\u002Fgithub.com\u002Fdanfinnie)\n - [Philip M. White](https:\u002F\u002Fgithub.com\u002Fphilipmw)\n - [Arlan Jaska](https:\u002F\u002Fgithub.com\u002Fajaska)\n - [Sean Walbran](https:\u002F\u002Fgithub.com\u002Fseanwalbran)\n - [Nathan Broadbent](https:\u002F\u002Fgithub.com\u002Fndbroadbent)\n - [Yuki Inoue](https:\u002F\u002Fgithub.com\u002FYuki-Inoue)\n - [Takumasa Ochi](https:\u002F\u002Fgithub.com\u002Faeroastro)\n - [Shai Coleman](https:\u002F\u002Fgithub.com\u002Fshaicoleman)\n - [Earlopain](https:\u002F\u002Fgithub.com\u002FEarlopain)\n\n[Michael Grosser](http:\u002F\u002Fgrosser.it)\u003Cbr\u002F>\nmichael@grosser.it\u003Cbr\u002F>\nLicense: MIT\u003Cbr\u002F>\n","grosser\u002Fparallel 是一个 Ruby 库，用于简化并加速并行处理。它支持通过进程、线程或 Ractors 来并行执行代码，充分利用多核 CPU 的计算能力，从而显著提高处理速度。该库特别适用于 map-reduce 操作和并行下载\u002F上传等场景。其核心功能包括使用多个进程加快 CPU 密集型任务的执行速度，利用线程优化 I\u002FO 阻塞操作，并且在 Ruby 3.0+ 中引入了实验性的 Ractors 以实现更高效的并行处理。此外，对于 ActiveRecord 用户，此库还提供了连接池管理建议来解决多线程环境下的数据库连接问题。MIT 许可证下开源，拥有活跃的社区支持。",2,"2026-06-11 03:14:18","top_language"]