celluloid-pmap 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ script: rake
2
+ rvm:
3
+ - 1.9.3
4
+ - ruby-head
5
+ - jruby-19mode
6
+ - jruby-head
7
+ - rbx-19mode
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in celluloid-pmap.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Jesse Wolgamott
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,103 @@
1
+ # Celluloid::Pmap
2
+
3
+ [![Build Status](https://travis-ci.org/jwo/celluloid-pmap.png?branch=master)](https://travis-ci.org/jwo/celluloid-pmap) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/jwo/celluloid-pmap)
4
+
5
+ Parallel Mapping using Celluloid
6
+
7
+ Celluloid Futures are wicked sweet, and when combined with a `pmap`
8
+ implementation AND a supervisor to keep the max threads down, you can be wicked
9
+ sweet too!
10
+
11
+ ### How does this happen?
12
+ ![celluloid](https://f.cloud.github.com/assets/123075/109654/7584c1fa-6a8c-11e2-9ad6-114818b7fbe4.png)
13
+
14
+ We use Celluloid Futures and Celluloid pool to execute blocks in parallel.
15
+
16
+ The pmap will return an array of values when all of the Futures have completed and return values (or return nil).
17
+
18
+ The pool can help to make sure you don't exceed your connection resources. A common use case for this is in Rails, you can easily exceed the default ActiveRecord connection size.
19
+
20
+ ### Inspiration for this code
21
+
22
+ Tony Arcieri created [celluloid](http://celluloid.io/), and the [simple_pmap example](https://github.com/celluloid/celluloid/blob/master/examples/simple_pmap.rb) from which this codebase started
23
+
24
+ ### Is this production ready?
25
+
26
+ I've used this implementation in several production systems over the last year. All complexity is with Celluloid (not 1.0 yet, but in my experience has been highly stable.)
27
+
28
+ ### Why is this a gem?
29
+
30
+ Because I've been implementing the same initializer code in every project I've worked on for the last 6 months. It was time to take a stand, man.
31
+
32
+ ### What rubies will this run on?
33
+
34
+ * 1.9.3
35
+ * ruby-head (2.0)
36
+ * jruby-19mode
37
+ * jruby-head
38
+ * rbx-19mode
39
+
40
+
41
+ ## Installation
42
+
43
+ Add this line to your application's Gemfile:
44
+
45
+ gem 'celluloid-pmap'
46
+
47
+ ## Usage
48
+
49
+ Default usage will execute in parallel. Simply pass a block to an Enumerable
50
+ (like an Array)
51
+
52
+ ```
53
+ puts "You'll see the puts happen instantly, and the sleep in parallel"
54
+
55
+ [55,65,75,85].pmap{|speed_limit| puts "I can't drive _#{speed_limit}_";
56
+ sleep(rand)}
57
+
58
+ => You'll see the puts happen instantly, and the sleep in parallel
59
+ "I can't drive _55_ ""I can't drive _65_ "
60
+ "I can't drive _75_ "
61
+ "I can't drive _85_ "
62
+ ```
63
+
64
+ Problem: When using with ActiveRecord, you can quickly run out of connections.
65
+ Answer: Specify the max number of threads (actors) to create at once!
66
+
67
+ ```
68
+ puts "You should see two distinct groups of timestamps, 3 seconds apart"
69
+ puts [1,2,3].pmap(2){|speed_limit| puts Time.now.tap { sleep(3) }}
70
+
71
+ => You should see two distinct groups of timestamps, 3 seconds apart
72
+ 2013-01-29 21:15:01 -0600
73
+ 2013-01-29 21:15:01 -0600
74
+ 2013-01-29 21:15:04 -0600
75
+ ```
76
+
77
+ We default pmap's threads to the number of Celluloid cores in the system.
78
+
79
+ ## When will this help?
80
+
81
+ * When the blocks are IO bound (like database or web queries)
82
+ * When you're running JRuby or Rubinius
83
+ * When you're running C Extensions
84
+
85
+ ## So what will this not help with?
86
+
87
+ * Pure math or ruby computations
88
+
89
+ ## Image Credit
90
+
91
+ Ben Scheirman (@subdigital) originally used the awesome Celluloid He-Man image
92
+ in a presentation on background workers. "He-Man and the Masters of the
93
+ Universe," AND "She-Ra: Princess of Power" are copyright Mattel.
94
+
95
+ More information on He-Man can be found at the unspeakably wow site: http://castlegrayskull.org
96
+
97
+ ## Contributing
98
+
99
+ 1. Fork it
100
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
101
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
102
+ 4. Push to the branch (`git push origin my-new-feature`)
103
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new('spec')
5
+
6
+ task :default => 'spec'
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'celluloid/pmap/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "celluloid-pmap"
8
+ gem.version = Celluloid::Pmap::VERSION
9
+ gem.authors = ["Jesse Wolgamott"]
10
+ gem.email = ["jesse@comalproductions.com"]
11
+ gem.description = %q{Easy Parallel Executing using Celluloid}
12
+ gem.summary = %q{ Celluloid Futures are wicked sweet, and when combined with a #pmap implementation AND a supervisor to keep the max threads down, you can be wicked sweet too!}
13
+ gem.homepage = "https://github.com/jwo/celluloid-pmap"
14
+ gem.license = "MIT"
15
+
16
+ gem.files = `git ls-files`.split($/)
17
+ gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.require_paths = ["lib"]
20
+
21
+ gem.add_dependency('celluloid', '~> 0.12')
22
+
23
+ gem.add_development_dependency "rake"
24
+ gem.add_development_dependency "rspec"
25
+ end
@@ -0,0 +1,24 @@
1
+ require 'celluloid'
2
+ require 'celluloid/pmap/parallel_map_worker'
3
+ require "celluloid/pmap/version"
4
+
5
+ module Celluloid
6
+ module Pmap
7
+
8
+ def self.included(base)
9
+ base.class_eval do
10
+
11
+ def pmap(size=Celluloid.cores, &block)
12
+ pool = Pmap::ParallelMapWorker.pool(size: size)
13
+ futures = map { |elem| pool.future :yielder, elem, &block }
14
+ futures.map { |future| future.value }
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ module Enumerable
23
+ include Celluloid::Pmap
24
+ end
@@ -0,0 +1,12 @@
1
+ require 'celluloid'
2
+ module Celluloid::Pmap
3
+
4
+ class ParallelMapWorker
5
+ include Celluloid
6
+
7
+ def yielder(element=nil, &block)
8
+ yield element
9
+ end
10
+ end
11
+
12
+ end
@@ -0,0 +1,5 @@
1
+ module Celluloid
2
+ module Pmap
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,14 @@
1
+ require 'celluloid/pmap/parallel_map_worker'
2
+
3
+ describe Celluloid::Pmap::ParallelMapWorker do
4
+
5
+ it "should execute the block we send" do
6
+ result = subject.yielder { 6 + 3 }
7
+ result.should eq(9)
8
+ end
9
+
10
+ it "should send in the argument to the block" do
11
+ result = subject.yielder(6) {|e| e + 3 }
12
+ result.should eq(9)
13
+ end
14
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe Celluloid::Pmap do
4
+
5
+ it 'should have a version number' do
6
+ Celluloid::Pmap::VERSION.should_not be_nil
7
+ end
8
+
9
+ it 'should still map correctly' do
10
+ [4,5,6,7].map{|x| x + 1}.should eq([5,6,7,8])
11
+ end
12
+
13
+ it 'should have same results when pmap' do
14
+ [4,5,6,7].pmap{|x| x + 1}.should eq([5,6,7,8])
15
+ end
16
+
17
+ it 'should sleep in sequence for map' do
18
+ expect {
19
+ [1,2,3].map{|x| x; sleep(1) }
20
+ }.to take_approximately(3).seconds
21
+ end
22
+
23
+ it 'should sleep in parallel for pmap' do
24
+ Celluloid.stub(:cores) { 4 }
25
+ expect {
26
+ [1,2,3].pmap{|x| x; sleep(1) }
27
+ }.to take_approximately(1).seconds
28
+ end
29
+
30
+ it 'should default to the number of cores on the machine' do
31
+ Celluloid.stub(:cores) { 4 }
32
+ expect {
33
+ [1,2,3,4,5,6].pmap{|x| x; sleep(1) }
34
+ }.to take_approximately(2).seconds
35
+ end
36
+
37
+ it 'can be set to many threads at once' do
38
+ expect {
39
+ [1,2,3,4,5,6].pmap(10) {|x| x; sleep(1) }
40
+ }.to take_approximately(1).seconds
41
+ end
42
+
43
+ it 'should be included in enumerable' do
44
+ Enumerable.ancestors.should include(Celluloid::Pmap)
45
+ end
46
+
47
+ end
@@ -0,0 +1,3 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'celluloid/pmap'
3
+ require 'support/benchmark_spec'
@@ -0,0 +1,26 @@
1
+ require 'benchmark'
2
+
3
+ RSpec::Matchers.define :take_approximately do |n|
4
+ chain :seconds do; end
5
+
6
+ match do |block|
7
+ @elapsed = Benchmark.realtime do
8
+ block.call
9
+ end
10
+ @elapsed.should be_within(0.2).of(n)
11
+ end
12
+
13
+ failure_message_for_should do |actual|
14
+ "expected block to take about #{expected} seconds, but took #{@elapsed}"
15
+ end
16
+
17
+ failure_message_for_should_not do |actual|
18
+ "expected block to not take about #{expected} seconds, but took #{@elapsed}"
19
+ end
20
+
21
+ description do
22
+ "take approximately #{expectely} seconds to execute"
23
+ end
24
+
25
+ end
26
+
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: celluloid-pmap
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jesse Wolgamott
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: celluloid
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '0.12'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '0.12'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: Easy Parallel Executing using Celluloid
63
+ email:
64
+ - jesse@comalproductions.com
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - .gitignore
70
+ - .rspec
71
+ - .travis.yml
72
+ - Gemfile
73
+ - LICENSE.txt
74
+ - README.md
75
+ - Rakefile
76
+ - celluloid-pmap.gemspec
77
+ - lib/celluloid/pmap.rb
78
+ - lib/celluloid/pmap/parallel_map_worker.rb
79
+ - lib/celluloid/pmap/version.rb
80
+ - spec/celluloid/pmap/parallel_map_worker_spec.rb
81
+ - spec/celluloid/pmap_spec.rb
82
+ - spec/spec_helper.rb
83
+ - spec/support/benchmark_spec.rb
84
+ homepage: https://github.com/jwo/celluloid-pmap
85
+ licenses:
86
+ - MIT
87
+ post_install_message:
88
+ rdoc_options: []
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ segments:
98
+ - 0
99
+ hash: 1634678292580827716
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ none: false
102
+ requirements:
103
+ - - ! '>='
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ segments:
107
+ - 0
108
+ hash: 1634678292580827716
109
+ requirements: []
110
+ rubyforge_project:
111
+ rubygems_version: 1.8.24
112
+ signing_key:
113
+ specification_version: 3
114
+ summary: ! 'Celluloid Futures are wicked sweet, and when combined with a #pmap implementation
115
+ AND a supervisor to keep the max threads down, you can be wicked sweet too!'
116
+ test_files:
117
+ - spec/celluloid/pmap/parallel_map_worker_spec.rb
118
+ - spec/celluloid/pmap_spec.rb
119
+ - spec/spec_helper.rb
120
+ - spec/support/benchmark_spec.rb