iprocess 4.0.0 → 5.0.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/README.md +12 -16
- data/iprocess.gemspec +2 -1
- data/lib/iprocess.rb +32 -43
- data/lib/iprocess/version.rb +1 -1
- data/test/setup.rb +3 -1
- data/test/support/inbox_class.rb +13 -0
- data/test/test_IProcess_class.rb +16 -17
- metadata +8 -4
data/README.md
CHANGED
@@ -12,11 +12,11 @@ __OVERVIEW__
|
|
12
12
|
__DESCRIPTION__
|
13
13
|
|
14
14
|
Provides a number of abstractions on top of spawning subprocesses and
|
15
|
-
interprocess communication. The API is simple
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
interprocess communication. The API is simple and supports both synchronous and
|
16
|
+
asynchronous(non-blocking) dispatch of subprocesses. It also supports implicit
|
17
|
+
interprocess communication that can be easily configured to use the serializer
|
18
|
+
of your choice(default is the [Marshal](http://rdoc.info/stdlib/core/Marshal)
|
19
|
+
module) if needs be.
|
20
20
|
|
21
21
|
__EXAMPLES__
|
22
22
|
|
@@ -52,17 +52,20 @@ __3.__
|
|
52
52
|
A demo of how you would spawn two subprocesses asynchronously:
|
53
53
|
|
54
54
|
class Inbox
|
55
|
+
attr_reader :msgs
|
56
|
+
|
55
57
|
def initialize
|
56
|
-
@
|
58
|
+
@msgs = []
|
57
59
|
end
|
58
60
|
|
59
61
|
def recv(msg)
|
60
|
-
@
|
62
|
+
@msgs << msg
|
61
63
|
end
|
62
64
|
end
|
63
65
|
inbox = Inbox.new
|
64
|
-
|
65
|
-
|
66
|
+
IProcess.spawn!(2, Inbox.new) { Process.pid }
|
67
|
+
sleep 0.1
|
68
|
+
p inbox.msgs
|
66
69
|
|
67
70
|
__SERIALIZERS__
|
68
71
|
|
@@ -106,13 +109,6 @@ __INSTALL__
|
|
106
109
|
|
107
110
|
$ gem install iprocess
|
108
111
|
|
109
|
-
__SEE ALSO__
|
110
|
-
|
111
|
-
- [XPool](https://github.com/robgleeson/xpool)
|
112
|
-
XPool is a UNIX process pool that was born inside IProcess but later extracted
|
113
|
-
into its own project. It might be interesting to you if you're interested in
|
114
|
-
concurrency and/or interprocess communication.
|
115
|
-
|
116
112
|
__LICENSE__
|
117
113
|
|
118
114
|
MIT. See LICENSE.txt.
|
data/iprocess.gemspec
CHANGED
@@ -7,7 +7,8 @@ Gem::Specification.new do |s|
|
|
7
7
|
s.authors = ["Rob Gleeson"]
|
8
8
|
s.email = 'rob@flowof.info'
|
9
9
|
s.homepage = 'https://github.com/robgleeson/iprocess'
|
10
|
-
s.summary = '
|
10
|
+
s.summary = 'A number of abstractions on top of spawning subprocesses ' \
|
11
|
+
'and interprocess communication.'
|
11
12
|
s.description = s.summary
|
12
13
|
|
13
14
|
s.files = `git ls-files`.each_line.map(&:chomp)
|
data/lib/iprocess.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
class IProcess
|
2
2
|
require 'ichannel'
|
3
3
|
require_relative 'iprocess/version'
|
4
|
+
|
4
5
|
#
|
5
6
|
# @return [#load,#dump]
|
6
7
|
# Returns the serializer used by IProcess.
|
7
8
|
#
|
8
|
-
def self.serializer
|
9
|
+
def self.serializer
|
9
10
|
@serializer || Marshal
|
10
11
|
end
|
11
12
|
|
@@ -19,9 +20,7 @@ class IProcess
|
|
19
20
|
end
|
20
21
|
|
21
22
|
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
# Spawn one or more subprocesses.
|
23
|
+
# Spawn one or more subprocesse(s).
|
25
24
|
#
|
26
25
|
# @param [Integer] number_of
|
27
26
|
# The number of subprocesses to spawn.
|
@@ -30,25 +29,35 @@ class IProcess
|
|
30
29
|
# The unit of work to execute in a subprocess.
|
31
30
|
#
|
32
31
|
# @return [Array<Object>]
|
33
|
-
# The return value
|
34
|
-
#
|
35
|
-
|
36
|
-
|
32
|
+
# The return value of the unit of work.
|
33
|
+
#
|
34
|
+
# @example
|
35
|
+
# IProcess.spawn 2 do
|
36
|
+
# {ok: true}
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
def self.spawn(number_of, obj = nil, &worker)
|
40
|
+
fork(number_of, obj, &worker).map(&:result)
|
37
41
|
end
|
38
42
|
|
39
43
|
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
# Spawn one or more subprocesses asynchronously.
|
44
|
+
# Spawn one or more subprocesse(s) asynchronously.
|
43
45
|
#
|
44
|
-
#
|
45
|
-
#
|
46
|
+
# @param [#recv] inbox
|
47
|
+
# An object who can receive messages through the {#recv} method.
|
46
48
|
#
|
47
|
-
#
|
48
|
-
#
|
49
|
+
# @param
|
50
|
+
# (see IProcess.spawn)
|
49
51
|
#
|
50
|
-
|
51
|
-
|
52
|
+
# @return [Array<IProcess>]
|
53
|
+
#
|
54
|
+
def self.spawn!(number_of, inbox, obj = nil, &worker)
|
55
|
+
forks = fork number_of, obj, &worker
|
56
|
+
forks.each do |subprocess|
|
57
|
+
Thread.new do
|
58
|
+
inbox.recv subprocess.result
|
59
|
+
end
|
60
|
+
end
|
52
61
|
end
|
53
62
|
|
54
63
|
def self.fork(number_of = 1, obj = nil, &worker)
|
@@ -61,10 +70,10 @@ class IProcess
|
|
61
70
|
|
62
71
|
#
|
63
72
|
# @param [#call] worker
|
64
|
-
#
|
73
|
+
# The unit of work to execute in a subprocess.
|
65
74
|
#
|
66
75
|
# @raise [ArgumentError]
|
67
|
-
# If
|
76
|
+
# If a worker is not given.
|
68
77
|
#
|
69
78
|
# @return [IProcess]
|
70
79
|
# Returns self.
|
@@ -72,7 +81,7 @@ class IProcess
|
|
72
81
|
def initialize(worker)
|
73
82
|
@worker = worker
|
74
83
|
@channel = nil
|
75
|
-
@pid
|
84
|
+
@pid = nil
|
76
85
|
unless @worker.respond_to?(:call)
|
77
86
|
raise ArgumentError,
|
78
87
|
"Expected worker to implement #{@worker.class}#call"
|
@@ -80,34 +89,14 @@ class IProcess
|
|
80
89
|
end
|
81
90
|
|
82
91
|
#
|
83
|
-
#
|
84
|
-
# An object that will receive messages.
|
85
|
-
#
|
86
|
-
# @return [void]
|
87
|
-
#
|
88
|
-
def report_to(obj)
|
89
|
-
thr = Thread.new do
|
90
|
-
Process.wait @pid
|
91
|
-
obj.recv @channel.recv
|
92
|
-
end
|
93
|
-
pid = Process.pid
|
94
|
-
at_exit do
|
95
|
-
is_parent = pid == Process.pid
|
96
|
-
if is_parent && thr.alive?
|
97
|
-
thr.join
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
#
|
103
|
-
# Executes a subprocess.
|
92
|
+
# Executes a unit of work in a subprocess.
|
104
93
|
#
|
105
94
|
# @return [Fixnum]
|
106
95
|
# The process ID of the spawned subprocess.
|
107
96
|
#
|
108
97
|
def execute
|
109
98
|
@channel = IChannel.new IProcess.serializer
|
110
|
-
@pid = fork { @channel.
|
99
|
+
@pid = fork { @channel.write(@worker.call) }
|
111
100
|
end
|
112
101
|
|
113
102
|
#
|
@@ -116,6 +105,6 @@ class IProcess
|
|
116
105
|
#
|
117
106
|
def result
|
118
107
|
Process.wait(@pid)
|
119
|
-
@channel.
|
108
|
+
@channel.recv
|
120
109
|
end
|
121
110
|
end
|
data/lib/iprocess/version.rb
CHANGED
data/test/setup.rb
CHANGED
data/test/test_IProcess_class.rb
CHANGED
@@ -1,25 +1,24 @@
|
|
1
|
-
require_relative
|
1
|
+
require_relative 'setup'
|
2
2
|
class IProcessTest < Test::Unit::TestCase
|
3
|
-
def
|
4
|
-
|
3
|
+
def test_spawn
|
4
|
+
results = IProcess.spawn(2) { :ok }
|
5
|
+
assert_equal [:ok, :ok], results
|
5
6
|
end
|
6
7
|
|
7
|
-
def
|
8
|
-
|
9
|
-
assert_equal [:hello, :hello], messages
|
10
|
-
end
|
11
|
-
|
12
|
-
def test_duck_typed_worker
|
13
|
-
messages = IProcess.spawn 2, worker.new
|
14
|
-
assert_equal [:hello, :hello], messages
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
def worker
|
19
|
-
Class.new do
|
8
|
+
def test_spawn_with_non_proc_worker
|
9
|
+
klass = Class.new do
|
20
10
|
def call
|
21
|
-
:
|
11
|
+
:ok
|
22
12
|
end
|
23
13
|
end
|
14
|
+
results = IProcess.spawn 2, klass.new
|
15
|
+
assert_equal [:ok, :ok], results
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_async_spawn!
|
19
|
+
inbox = Inbox.new
|
20
|
+
IProcess.spawn!(2, inbox) { {ok: true} }
|
21
|
+
sleep 0.1
|
22
|
+
assert_equal [{ok: true}, {ok: true}], inbox.messages
|
24
23
|
end
|
25
24
|
end
|
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:
|
4
|
+
version: 5.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-01-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ichannel
|
@@ -91,7 +91,8 @@ dependencies:
|
|
91
91
|
- - ! '>='
|
92
92
|
- !ruby/object:Gem::Version
|
93
93
|
version: '0'
|
94
|
-
description:
|
94
|
+
description: A number of abstractions on top of spawning subprocesses and interprocess
|
95
|
+
communication.
|
95
96
|
email: rob@flowof.info
|
96
97
|
executables: []
|
97
98
|
extensions: []
|
@@ -110,6 +111,7 @@ files:
|
|
110
111
|
- lib/iprocess.rb
|
111
112
|
- lib/iprocess/version.rb
|
112
113
|
- test/setup.rb
|
114
|
+
- test/support/inbox_class.rb
|
113
115
|
- test/test_IProcess_class.rb
|
114
116
|
homepage: https://github.com/robgleeson/iprocess
|
115
117
|
licenses: []
|
@@ -134,8 +136,10 @@ rubyforge_project: ! '[none]'
|
|
134
136
|
rubygems_version: 1.8.23
|
135
137
|
signing_key:
|
136
138
|
specification_version: 3
|
137
|
-
summary:
|
139
|
+
summary: A number of abstractions on top of spawning subprocesses and interprocess
|
140
|
+
communication.
|
138
141
|
test_files:
|
139
142
|
- test/setup.rb
|
143
|
+
- test/support/inbox_class.rb
|
140
144
|
- test/test_IProcess_class.rb
|
141
145
|
has_rdoc:
|