iprocess 1.0.1 → 1.0.2
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/README.md +15 -7
- data/lib/iprocess/channel.rb +31 -7
- data/lib/iprocess/{delegate.rb → delegator.rb} +1 -1
- data/lib/iprocess/job.rb +20 -15
- data/lib/iprocess/version.rb +1 -1
- data/lib/iprocess.rb +4 -4
- data/test/test_IProcess_Job_class.rb +24 -0
- data/test/test_IProcess_class.rb +3 -1
- metadata +11 -11
data/README.md
CHANGED
@@ -4,7 +4,7 @@ __OVERVIEW__
|
|
4
4
|
| Project | IProcess
|
5
5
|
|:----------------|:--------------------------------------------------
|
6
6
|
| Homepage | https://github.com/robgleeson/IProcess
|
7
|
-
| Documentation | http://rubydoc.info/gems/
|
7
|
+
| Documentation | http://rubydoc.info/gems/iprocess/frames
|
8
8
|
| Author | Rob Gleeson
|
9
9
|
|
10
10
|
|
@@ -21,13 +21,21 @@ __WHY?__
|
|
21
21
|
|
22
22
|
I wanted to be able to:
|
23
23
|
|
24
|
-
*
|
25
|
-
|
26
|
-
(that was for a IRC bot evaluating Ruby code).
|
27
|
-
|
28
|
-
* Spawn multiple parallel jobs, then collect and send back Ruby objects to the
|
29
|
-
parent process.
|
24
|
+
* Share Ruby objects between a subprocess and its parent process.
|
25
|
+
* Share Ruby objects between multiple subprocesses running in parallel and their parent.
|
30
26
|
|
27
|
+
|
28
|
+
__COST?__
|
29
|
+
|
30
|
+
If you're using IProcess for parallelism, a subprocess will cost you more than
|
31
|
+
a thread (in terms of time to create the subprocess, and the memory it consumes
|
32
|
+
- no implementation IProcess supports has a CoW-friendly garbage collector).
|
33
|
+
|
34
|
+
Despite the GIL on CRuby, for IO bound operations it can run threads in
|
35
|
+
parallel and may perform better. For long running non-IO bound operations,
|
36
|
+
though, parallel subprocesses usually outperform CRuby threads. You should
|
37
|
+
profile and benchmark IProcess and threads for your use-case before choosing
|
38
|
+
either. IProcess may be better, or it may be worse.
|
31
39
|
|
32
40
|
__EXAMPLES__
|
33
41
|
|
data/lib/iprocess/channel.rb
CHANGED
@@ -15,6 +15,26 @@ class IProcess::Channel
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
+
#
|
19
|
+
# Is the channel closed?
|
20
|
+
#
|
21
|
+
# @return [Boolean]
|
22
|
+
# Returns true if the channel is closed.
|
23
|
+
#
|
24
|
+
def closed?
|
25
|
+
@reader.closed? && @writer.closed?
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# Is the channel open?
|
30
|
+
#
|
31
|
+
# @return [Boolean]
|
32
|
+
# Returns true if the channel is open.
|
33
|
+
#
|
34
|
+
def open?
|
35
|
+
!closed?
|
36
|
+
end
|
37
|
+
|
18
38
|
#
|
19
39
|
# Write a object to the channel.
|
20
40
|
#
|
@@ -22,9 +42,11 @@ class IProcess::Channel
|
|
22
42
|
# A object to add to the channel.
|
23
43
|
#
|
24
44
|
def write object
|
25
|
-
|
26
|
-
|
27
|
-
|
45
|
+
if open?
|
46
|
+
@reader.close
|
47
|
+
@writer.write Marshal.dump(object)
|
48
|
+
@writer.close
|
49
|
+
end
|
28
50
|
end
|
29
51
|
|
30
52
|
#
|
@@ -34,10 +56,12 @@ class IProcess::Channel
|
|
34
56
|
# The object added to the channel.
|
35
57
|
#
|
36
58
|
def recv
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
59
|
+
if open?
|
60
|
+
@writer.close
|
61
|
+
obj = Marshal.load(@reader.read)
|
62
|
+
@reader.close
|
63
|
+
obj
|
64
|
+
end
|
41
65
|
end
|
42
66
|
|
43
67
|
end
|
data/lib/iprocess/job.rb
CHANGED
@@ -1,21 +1,25 @@
|
|
1
1
|
class IProcess::Job
|
2
2
|
|
3
3
|
#
|
4
|
-
#
|
4
|
+
# @overload spawn(number_of_jobs = 1, worker)
|
5
5
|
#
|
6
|
-
#
|
7
|
-
# The number of jobs to spawn.
|
6
|
+
# Spawn one or more jobs to be run in parallel.
|
8
7
|
#
|
9
|
-
#
|
10
|
-
#
|
8
|
+
# @param [Integer] number_of_jobs
|
9
|
+
# The number of jobs to spawn.
|
11
10
|
#
|
12
|
-
#
|
13
|
-
#
|
11
|
+
# @param [#call] worker
|
12
|
+
# The unit of work to execute in one or more jobs.
|
14
13
|
#
|
15
|
-
|
14
|
+
# @return [Array<Object>]
|
15
|
+
# The return value of one or more workers.
|
16
|
+
#
|
17
|
+
def self.spawn number_of_jobs = 1, obj = nil, &worker
|
18
|
+
worker = obj || worker
|
19
|
+
|
16
20
|
jobs =
|
17
21
|
Array.new(number_of_jobs) do
|
18
|
-
job = IProcess::Job.new(
|
22
|
+
job = IProcess::Job.new(worker)
|
19
23
|
job.execute
|
20
24
|
job
|
21
25
|
end
|
@@ -26,7 +30,7 @@ class IProcess::Job
|
|
26
30
|
end
|
27
31
|
|
28
32
|
#
|
29
|
-
# @param [
|
33
|
+
# @param [#call] worker
|
30
34
|
# The unit of work to execute in a subprocess.
|
31
35
|
#
|
32
36
|
# @raise [ArgumentError]
|
@@ -35,14 +39,15 @@ class IProcess::Job
|
|
35
39
|
# @return [IProcess::Job]
|
36
40
|
# Returns self.
|
37
41
|
#
|
38
|
-
def initialize
|
39
|
-
unless block_given?
|
40
|
-
raise ArgumentError, 'No block given.'
|
41
|
-
end
|
42
|
-
|
42
|
+
def initialize worker
|
43
43
|
@worker = worker
|
44
44
|
@channel = nil
|
45
45
|
@pid = nil
|
46
|
+
|
47
|
+
unless @worker.respond_to?(:call)
|
48
|
+
raise ArgumentError,
|
49
|
+
"Expected worker to implement #{@worker.class}#call"
|
50
|
+
end
|
46
51
|
end
|
47
52
|
|
48
53
|
#
|
data/lib/iprocess/version.rb
CHANGED
data/lib/iprocess.rb
CHANGED
@@ -5,12 +5,11 @@ class IProcess
|
|
5
5
|
#
|
6
6
|
def initialize &block
|
7
7
|
@variables = SortedSet.new
|
8
|
+
@scope = nil
|
8
9
|
|
9
10
|
if block_given?
|
10
11
|
@scope = block.binding
|
11
|
-
IProcess::
|
12
|
-
else
|
13
|
-
@scope = nil
|
12
|
+
IProcess::Delegator.new(self).instance_eval(&block)
|
14
13
|
end
|
15
14
|
end
|
16
15
|
|
@@ -85,6 +84,7 @@ class IProcess
|
|
85
84
|
scope.eval("#{channel.name} = Thread.current[:__iprocess_obj__]")
|
86
85
|
end
|
87
86
|
|
87
|
+
Thread.current[:__iprocess_obj__] = nil
|
88
88
|
pid
|
89
89
|
end
|
90
90
|
|
@@ -94,4 +94,4 @@ require 'set'
|
|
94
94
|
require 'iprocess/version'
|
95
95
|
require 'iprocess/channel'
|
96
96
|
require 'iprocess/job'
|
97
|
-
require 'iprocess/
|
97
|
+
require 'iprocess/delegator'
|
@@ -4,6 +4,30 @@ context IProcess::Job do
|
|
4
4
|
topic = IProcess::Job.spawn(2) { :ok }
|
5
5
|
topic.must_equal([:ok, :ok])
|
6
6
|
end
|
7
|
+
|
8
|
+
it 'must spawn non-Proc workers and return the result of each.' do
|
9
|
+
worker = Class.new do
|
10
|
+
def call
|
11
|
+
:ok
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
topic = IProcess::Job.spawn(2, worker.new)
|
16
|
+
topic.must_equal([:ok, :ok])
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'must accept any object responding to #call.' do
|
20
|
+
mock = MiniTest::Mock.new
|
21
|
+
mock.expect(:call, :ok)
|
22
|
+
|
23
|
+
IProcess::Job.spawn(1, mock)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'initialize' do
|
28
|
+
it "must raise a ArgumentError if not given a object responding to #call" do
|
29
|
+
proc { IProcess::Job.new("") }.must_raise(ArgumentError)
|
30
|
+
end
|
7
31
|
end
|
8
32
|
end
|
9
33
|
|
data/test/test_IProcess_class.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: iprocess
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-01
|
12
|
+
date: 2012-03-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: yard
|
16
|
-
requirement: &
|
16
|
+
requirement: &70154156887500 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0.7'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70154156887500
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: redcarpet
|
27
|
-
requirement: &
|
27
|
+
requirement: &70154156887040 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '1.17'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70154156887040
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: minitest
|
38
|
-
requirement: &
|
38
|
+
requirement: &70154156886580 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '2.6'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70154156886580
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rake
|
49
|
-
requirement: &
|
49
|
+
requirement: &70154156886120 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,7 +54,7 @@ dependencies:
|
|
54
54
|
version: 0.9.2
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70154156886120
|
58
58
|
description: A Domain Specific Language(DSL) for sharing Ruby objectsbetween processes
|
59
59
|
on UNIX-like operating systems.
|
60
60
|
email: rob@flowof.info
|
@@ -73,7 +73,7 @@ files:
|
|
73
73
|
- iprocess.gemspec
|
74
74
|
- lib/iprocess.rb
|
75
75
|
- lib/iprocess/channel.rb
|
76
|
-
- lib/iprocess/
|
76
|
+
- lib/iprocess/delegator.rb
|
77
77
|
- lib/iprocess/job.rb
|
78
78
|
- lib/iprocess/version.rb
|
79
79
|
- test/setup.rb
|