├── .gitignore ├── .travis.yml ├── Gemfile ├── README.md ├── Rakefile ├── bin ├── console └── setup ├── enumerator-parallel.gemspec ├── lib ├── enumerator-parallel.rb └── enumerator-parallel │ └── version.rb └── test ├── minitest_helper.rb └── test_parallel_enumerable.rb /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /Gemfile.lock 4 | /_yardoc/ 5 | /coverage/ 6 | /doc/ 7 | /pkg/ 8 | /spec/reports/ 9 | /tmp/ 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | sudo: false 3 | cache: 4 | - bundler 5 | 6 | bundler: 7 | rvm: 8 | - 2.2 9 | - 2.1 10 | - 2.0 11 | - ruby-head 12 | - jruby-head 13 | - rbx-2 14 | 15 | notifications: 16 | email: false -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'pry' 4 | gemspec 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Enumerator::Parallel 2 | 3 | ```ruby 4 | require 'enumerator-parallel' 5 | 6 | [1, 2, 3].par(processes: 3).each { |n| sleep 1; p n } 7 | ``` 8 | 3 times fater! wow wow wow 9 | 10 | `enumerator-parallel` keep order of results \(^o^) 11 | 12 | ```ruby 13 | [1, 2, 3].par(threads: 3).map { |n| sleep 1; p n } 14 | #=> [1, 2, 3] 15 | 16 | [1, 2, 3].par(proceses: 3).select { |n| sleep 1; n > 1 } 17 | #=> [2, 3] 18 | 19 | (1..10).par(threads: 10).reject { |n| sleep 1; n.odd? } 20 | #=> [2, 4, 6, 8, 10] 21 | ``` 22 | 23 | ```ruby 24 | (1..10).par(threads: 10).all? { |n| n > 0 } 25 | #=> true 26 | 27 | (1..10).par(threads: 10).any? { |n| n == 10 } 28 | #=> true 29 | ``` 30 | 31 | #### You need to take care of side-effecting 32 | While keeping order of results, order of calling `block` is randomly. 33 | 34 | 35 | 36 | ```ruby 37 | $global_var = 1 38 | (0..10).par(threads: 3).map { |n| sleep rand; $global_var += 1 } 39 | ``` 40 | You could find difference between ↑ and ↓ :D 41 | 42 | ```ruby 43 | $global_var = 1 44 | (0..10).map { |n| sleep rand; $global_var += 1 } 45 | ``` 46 | 47 | ## Installation 48 | 49 | Have it your way. 50 | 51 | $ echo "gem 'enumerator-parallel'" >> Gemfile; bundle 52 | 53 | or 54 | 55 | $ gem install enumerator-parallel 56 | 57 | 58 | ## Development 59 | 60 | After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment. 61 | 62 | To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). 63 | 64 | ## License 65 | 66 | MIT license (© 2015 Kazuki Tanaka) 67 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rake/testtask" 3 | 4 | Rake::TestTask.new(:test) do |t| 5 | t.libs << "test" 6 | end 7 | 8 | task :default => :test 9 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "enumerator-parallel" 5 | 6 | # You can add fixtures and/or initialization code here to make experimenting 7 | # with your gem easier. You can also use a different console, if you like. 8 | 9 | # (If you use this, don't forget to add pry to your Gemfile!) 10 | # require "pry" 11 | # Pry.start 12 | 13 | require "irb" 14 | IRB.start 15 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | 5 | bundle install 6 | 7 | # Do any other automated setup that you need to do here 8 | -------------------------------------------------------------------------------- /enumerator-parallel.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'enumerator-parallel/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "enumerator-parallel" 8 | spec.version = ParallelEnumerable::VERSION 9 | spec.authors = ["gogotanaka"] 10 | spec.email = ["mail@tanakakazuki.com"] 11 | 12 | spec.summary = %q{ Simple wrapper between enumerator and parallel. } 13 | spec.description = %q{ Simple wrapper between enumerator and parallel. } 14 | spec.homepage = "https://github.com/gogotanaka/enumerator-parallel" 15 | 16 | spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } 17 | spec.bindir = "exe" 18 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } 19 | spec.require_paths = ["lib"] 20 | 21 | spec.add_dependency 'parallel', ['>=1.4.1'] 22 | 23 | spec.add_development_dependency 'bundler', ['>= 1.0.0'] 24 | spec.add_development_dependency 'rake', ['>= 0'] 25 | spec.add_development_dependency "minitest" 26 | end 27 | -------------------------------------------------------------------------------- /lib/enumerator-parallel.rb: -------------------------------------------------------------------------------- 1 | require "enumerator-parallel/version" 2 | require "parallel" 3 | 4 | module Enumerable 5 | def parallel(options = {}) 6 | Enumerator::Parallel.new(self, options) 7 | end 8 | alias par parallel 9 | end 10 | 11 | class Enumerator::Parallel 12 | def initialize(enum, options) 13 | mappings = { processes: :in_processes, threads: :in_threads } 14 | @enum, @options = enum.to_a, Hash[options.map { |k, v| [(mappings[k] || k), v] }] 15 | end 16 | 17 | def each(&block) 18 | ::Parallel.each(@enum, @options, &block) 19 | end 20 | 21 | def map(&block) 22 | ::Parallel.map(@enum, @options, &block) 23 | end 24 | 25 | def all?(&block) 26 | map(&block).all? 27 | end 28 | 29 | def any?(&block) 30 | map(&block).any? 31 | end 32 | 33 | %w|group_by select reject|.each do |mth| 34 | define_method(mth) do |*args, &block| 35 | map_num = map(&block) 36 | @enum.send(mth).with_index { |_, i| map_num[i] } 37 | end 38 | end 39 | 40 | def count(&block) 41 | map(&block).count(true) 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/enumerator-parallel/version.rb: -------------------------------------------------------------------------------- 1 | module ParallelEnumerable 2 | VERSION = "0.1.1" 3 | end 4 | -------------------------------------------------------------------------------- /test/minitest_helper.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) 2 | require 'enumerator-parallel' 3 | 4 | require 'minitest/autorun' 5 | require 'pry' 6 | -------------------------------------------------------------------------------- /test/test_parallel_enumerable.rb: -------------------------------------------------------------------------------- 1 | require 'minitest_helper' 2 | 3 | class TestParallelEnumerable < Minitest::Test 4 | def setup 5 | @enum3 = { a: 1, b: 2, c: 3 } 6 | @enum20 = (1..20).to_a 7 | 8 | @enum_par3 = { a: 1, b: 2, c: 3 } 9 | @enum_par20 = (1..20).to_a.par(threads: 20) 10 | end 11 | 12 | def test_main 13 | assert_equal @enum20, @enum_par20.map { |n| sleep 1; n } 14 | assert_equal @enum20.select { |n| n < 10 }, @enum_par20.select { |n| sleep 1; n < 10 } 15 | assert_equal @enum20.reject { |n| n < 10 }, @enum_par20.reject { |n| sleep 1; n < 10 } 16 | 17 | assert @enum_par20.all? { |n| sleep 1; n > 0 } 18 | assert @enum_par20.any? { |n| sleep 1; n == 1 } 19 | 20 | assert_equal @enum20.count { |x| x%2==0 }, @enum_par20.count { |x| sleep 1; x%2==0 } 21 | assert_equal @enum20.group_by { |x| x%2 }, @enum_par20.group_by { |x| x%2 } 22 | end 23 | end 24 | --------------------------------------------------------------------------------