dataflow 0.3.0 → 0.3.1
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.textile +99 -0
- data/dataflow.rb +8 -3
- data/examples/barrier.rb +9 -0
- data/examples/flow.rb +20 -0
- data/examples/future_queue.rb +11 -0
- data/spec/anonymous_variables_spec.rb +21 -0
- data/spec/forker_spec.rb +28 -0
- metadata +6 -1
data/README.textile
CHANGED
@@ -58,6 +58,20 @@ local do |x, y, z|
|
|
58
58
|
end
|
59
59
|
</pre>
|
60
60
|
|
61
|
+
<pre>
|
62
|
+
# Module methods version
|
63
|
+
|
64
|
+
Dataflow.local do |x, y, z|
|
65
|
+
# notice how the order automatically gets resolved
|
66
|
+
Thread.new { Dataflow.unify y, x + 2 }
|
67
|
+
Thread.new { Dataflow.unify z, y + 3 }
|
68
|
+
Thread.new { Dataflow.unify x, 1 }
|
69
|
+
z #=> 6
|
70
|
+
end
|
71
|
+
|
72
|
+
# Note that a gobal Dataflow.declare is not supported
|
73
|
+
</pre>
|
74
|
+
|
61
75
|
<pre>
|
62
76
|
# Instance variables
|
63
77
|
class AnimalHouse
|
@@ -118,6 +132,91 @@ local do |x, y, z|
|
|
118
132
|
end
|
119
133
|
</pre>
|
120
134
|
|
135
|
+
<pre>
|
136
|
+
include Dataflow
|
137
|
+
|
138
|
+
# flow without parameters
|
139
|
+
local do |x|
|
140
|
+
flow do
|
141
|
+
# other stuff
|
142
|
+
unify x, 1337
|
143
|
+
end
|
144
|
+
x #=> 1337
|
145
|
+
end
|
146
|
+
|
147
|
+
# flow with an output parameter
|
148
|
+
local do |x|
|
149
|
+
flow(x) do
|
150
|
+
# other stuff
|
151
|
+
1337
|
152
|
+
end
|
153
|
+
x #=> 1337
|
154
|
+
end
|
155
|
+
</pre>
|
156
|
+
|
157
|
+
<pre>
|
158
|
+
# barrier
|
159
|
+
include Dataflow
|
160
|
+
|
161
|
+
local do |lock1, lock2|
|
162
|
+
flow { unify lock1, :unlocked }
|
163
|
+
flow { unify lock2, :unlocked }
|
164
|
+
barrier lock1, lock2
|
165
|
+
puts "Barrier broken!"
|
166
|
+
end
|
167
|
+
</pre>
|
168
|
+
|
169
|
+
<pre>
|
170
|
+
# FutureQueue
|
171
|
+
include Dataflow
|
172
|
+
|
173
|
+
local do |queue, first, second|
|
174
|
+
unify queue, Dataflow::FutureQueue.new
|
175
|
+
queue.pop first
|
176
|
+
queue.push 1
|
177
|
+
queue.push 2
|
178
|
+
queue.pop second
|
179
|
+
first #=> 1
|
180
|
+
second #=> 2
|
181
|
+
end
|
182
|
+
</pre>
|
183
|
+
|
184
|
+
h1. Anonymous variables
|
185
|
+
|
186
|
+
Sometimes you may want to pack a data structure with variables that do not need to be referenced with labels. For those cases anonymous variables are a good choice, here are some options:
|
187
|
+
|
188
|
+
<pre>
|
189
|
+
include Dataflow
|
190
|
+
Array.new(3) { Dataflow::Variable.new }
|
191
|
+
Array.new(3) { Dataflow.local }
|
192
|
+
Array.new(3) { local }
|
193
|
+
# and technically not anonymous
|
194
|
+
Array.new(3) { local {|v| v } }
|
195
|
+
</pre>
|
196
|
+
|
197
|
+
h1. Debugging
|
198
|
+
|
199
|
+
If you are having trouble and need to debug dataflow variables, simply call #inspect.
|
200
|
+
|
201
|
+
If the variable has already been bound, it call inspect on its bound value like normal.However, if the variable is not bound yet then you will get a special string that contains the proxies #__id__ that you can use to track down which proxy objects are being passed around to which parts of your program:
|
202
|
+
<pre>
|
203
|
+
include Dataflow
|
204
|
+
local do |my_var|
|
205
|
+
my_var.inspect # => #<Dataflow::Variable:2637860 unbound>
|
206
|
+
end
|
207
|
+
</pre>
|
208
|
+
|
209
|
+
h1. Fork method customization
|
210
|
+
|
211
|
+
By default both #flow and #need_later use Thread.fork as their fork method. Youc an access the fork method via Dataflow.forker.
|
212
|
+
|
213
|
+
If you would like to use a custom forker, simple set it to an object that responds to #call and internally calls a block passed to it (for an example of a synchronous forker, see spec/forker_spec.rb):
|
214
|
+
<pre>
|
215
|
+
Dataflow.forker = MyClass.method(:fork_with_threadpool)
|
216
|
+
</pre>
|
217
|
+
|
218
|
+
Also note that #flow is used interally by #need_later, in case you want to override that specifically.
|
219
|
+
|
121
220
|
h1. Ports using Dataflow
|
122
221
|
|
123
222
|
Ports are an extension of the declarative concurrent model to support nondeterministic behavior. They accomplish this through the use of a single state variable. Ports are also inspired by the Oz language.
|
data/dataflow.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
require 'monitor'
|
2
2
|
|
3
3
|
module Dataflow
|
4
|
-
VERSION = "0.3.
|
4
|
+
VERSION = "0.3.1"
|
5
|
+
class << self
|
6
|
+
attr_accessor :forker
|
7
|
+
end
|
8
|
+
self.forker = Thread.method(:fork)
|
5
9
|
|
6
10
|
def self.included(cls)
|
7
11
|
class << cls
|
@@ -19,6 +23,7 @@ module Dataflow
|
|
19
23
|
end
|
20
24
|
|
21
25
|
def local(&block)
|
26
|
+
return Variable.new unless block_given?
|
22
27
|
vars = Array.new(block.arity) { Variable.new }
|
23
28
|
block.call *vars
|
24
29
|
end
|
@@ -36,7 +41,7 @@ module Dataflow
|
|
36
41
|
end
|
37
42
|
|
38
43
|
def flow(output=nil, &block)
|
39
|
-
|
44
|
+
Dataflow.forker.call do
|
40
45
|
result = block.call
|
41
46
|
unify output, result if output
|
42
47
|
end
|
@@ -44,7 +49,7 @@ module Dataflow
|
|
44
49
|
|
45
50
|
def need_later(&block)
|
46
51
|
local do |future|
|
47
|
-
flow {
|
52
|
+
flow(future) { block.call }
|
48
53
|
future
|
49
54
|
end
|
50
55
|
end
|
data/examples/barrier.rb
ADDED
data/examples/flow.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../dataflow"
|
2
|
+
include Dataflow
|
3
|
+
|
4
|
+
# flow without parameters
|
5
|
+
local do |x|
|
6
|
+
flow do
|
7
|
+
# other stuff
|
8
|
+
unify x, 1337
|
9
|
+
end
|
10
|
+
puts x
|
11
|
+
end
|
12
|
+
|
13
|
+
# flow with an output parameter
|
14
|
+
local do |x|
|
15
|
+
flow(x) do
|
16
|
+
# other stuff
|
17
|
+
1337
|
18
|
+
end
|
19
|
+
puts x
|
20
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../dataflow"
|
2
|
+
include Dataflow
|
3
|
+
|
4
|
+
local do |queue, first, second|
|
5
|
+
unify queue, Dataflow::FutureQueue.new
|
6
|
+
queue.pop first
|
7
|
+
queue.push 1
|
8
|
+
queue.push 2
|
9
|
+
queue.pop second
|
10
|
+
puts "first: #{first}, second: #{second}"
|
11
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/spec_helper"
|
2
|
+
|
3
|
+
describe 'Using an anonymous variable' do
|
4
|
+
it 'works with Variable instances' do
|
5
|
+
container = [Dataflow::Variable.new]
|
6
|
+
unify container.first, 1337
|
7
|
+
container.first.should == 1337
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'works with Dataflow.local' do
|
11
|
+
container = [Dataflow.local]
|
12
|
+
unify container.first, 1337
|
13
|
+
container.first.should == 1337
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'works with #local' do
|
17
|
+
container = [local]
|
18
|
+
unify container.first, 1337
|
19
|
+
container.first.should == 1337
|
20
|
+
end
|
21
|
+
end
|
data/spec/forker_spec.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/spec_helper"
|
2
|
+
|
3
|
+
describe 'Setting a customer forker' do
|
4
|
+
before(:all) do
|
5
|
+
@original_forker = Dataflow.forker
|
6
|
+
Dataflow.forker = Class.new do
|
7
|
+
def self.synchronous_forker(&block)
|
8
|
+
block.call
|
9
|
+
end
|
10
|
+
end.method(:synchronous_forker)
|
11
|
+
end
|
12
|
+
|
13
|
+
after(:all) do
|
14
|
+
Dataflow.forker = @original_forker
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'uses the custom forker in #flow' do
|
18
|
+
local do |my_var|
|
19
|
+
flow(my_var) { 1337 }
|
20
|
+
my_var.should == 1337
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'uses the custom forker in #need_later' do
|
25
|
+
my_var = need_later { 1337 }
|
26
|
+
my_var.should == 1337
|
27
|
+
end
|
28
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dataflow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Larry Diehl
|
@@ -31,9 +31,12 @@ files:
|
|
31
31
|
- dataflow/equality.rb
|
32
32
|
- dataflow/future_queue.rb
|
33
33
|
- dataflow/port.rb
|
34
|
+
- examples/barrier.rb
|
34
35
|
- examples/data_driven.rb
|
35
36
|
- examples/dataflow_http_gets.rb
|
37
|
+
- examples/flow.rb
|
36
38
|
- examples/future_http_gets.rb
|
39
|
+
- examples/future_queue.rb
|
37
40
|
- examples/instance_variables.rb
|
38
41
|
- examples/laziness.rb
|
39
42
|
- examples/local_variables.rb
|
@@ -69,11 +72,13 @@ specification_version: 2
|
|
69
72
|
summary: Dataflow concurrency for Ruby (inspired by the Oz language)
|
70
73
|
test_files:
|
71
74
|
- spec/actor_spec.rb
|
75
|
+
- spec/anonymous_variables_spec.rb
|
72
76
|
- spec/barrier_spec.rb
|
73
77
|
- spec/by_need_spec.rb
|
74
78
|
- spec/dataflow_spec.rb
|
75
79
|
- spec/equality_spec.rb
|
76
80
|
- spec/flow_spec.rb
|
81
|
+
- spec/forker_spec.rb
|
77
82
|
- spec/future_queue_spec.rb
|
78
83
|
- spec/inspect_spec.rb
|
79
84
|
- spec/need_later_spec.rb
|