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.
@@ -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.
@@ -1,7 +1,11 @@
1
1
  require 'monitor'
2
2
 
3
3
  module Dataflow
4
- VERSION = "0.3.0"
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
- Thread.new do
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 { unify future, block.call }
52
+ flow(future) { block.call }
48
53
  future
49
54
  end
50
55
  end
@@ -0,0 +1,9 @@
1
+ require "#{File.dirname(__FILE__)}/../dataflow"
2
+ include Dataflow
3
+
4
+ local do |lock1, lock2|
5
+ flow { unify lock1, :unlocked }
6
+ flow { unify lock2, :unlocked }
7
+ barrier lock1, lock2
8
+ puts "Barrier broken!"
9
+ end
@@ -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
@@ -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.0
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