trenza 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +70 -0
- data/examples/downloads.rb +22 -0
- data/examples/slow_calculator.rb +29 -0
- data/lib/trenza/blank_slate.rb +7 -0
- data/lib/trenza/lazy.rb +31 -0
- data/lib/trenza/parallel.rb +27 -0
- data/lib/trenza/proxy_builders.rb +13 -0
- data/lib/trenza.rb +4 -0
- metadata +52 -0
data/README.md
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# Trenza
|
2
|
+
|
3
|
+
Trenza is the spanish word for *braid* or *plait*.
|
4
|
+
|
5
|
+
> plait |plāt, plat| (noun) a single length of hair or other flexible material made up of three or more interlaced strands.
|
6
|
+
|
7
|
+
![Trenza](http://dl.dropbox.com/u/521377/trenza_cinco.jpg)
|
8
|
+
|
9
|
+
Trenza is also an experiment in dynamic programming inspired by the reading of Paolo Perrotta's *“Metaprogramming Ruby”* (an awesome book, by the way), and in evaluation models and strategies, inspired in my late adventures with Erlang and Haskell.
|
10
|
+
|
11
|
+
Trenza provides two methods to every Ruby object: `lazy` and `parallel`. Those two methods return an object that behaves exactly the same way the old one, except that, instead or evaluating its methods right away when they're called, they do it in a *lazy* or *parallel* way.
|
12
|
+
|
13
|
+
## *Lazy* objects
|
14
|
+
|
15
|
+
*Lazy* objects defer the actual evaluation of its methods until the moment its really needed:
|
16
|
+
|
17
|
+
class Wadus
|
18
|
+
def calculate
|
19
|
+
# whatever
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
wadus1 = Wadus.new.lazy
|
24
|
+
wadus2 = Wadus.new.lazy
|
25
|
+
|
26
|
+
x = wadus1.calculate
|
27
|
+
y = wadus2.calculate
|
28
|
+
# no calculation is actually done
|
29
|
+
|
30
|
+
puts x # now wadus1.calculate is run in order to print it
|
31
|
+
# wadus2.calculate never gets run since its not needed
|
32
|
+
|
33
|
+
## *Parallel* objects
|
34
|
+
|
35
|
+
*Parallel* objects are similar to *lazy* objects, but instead of deferring the whole evaluation of the method, they start it in the background and follow with your program. Whenever the actual return value is needed, then and only then will your program for the calculation to end (in case it hadn't ended already). This way your programs can become massively parallel without changing your programming style at all:
|
36
|
+
|
37
|
+
class Wadus
|
38
|
+
def calculate
|
39
|
+
# whatever
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
wadus1 = Wadus.new.parallel
|
44
|
+
wadus2 = Wadus.new.parallel
|
45
|
+
|
46
|
+
x = wadus1.calculate # calculation is started in the background, your program continues
|
47
|
+
y = wadus2.calculate # calculation is started in the background, your program continues
|
48
|
+
|
49
|
+
...
|
50
|
+
|
51
|
+
puts x + y # in case they hadn't finished already, now your program will wait for the
|
52
|
+
# calculations to finished, since the return values are needed
|
53
|
+
|
54
|
+
Please note that Trenza uses the underlying Ruby's `Thread` class implementation, so the actual kind of parallelism achieved depends greatly on the Ruby implementation you're using. Check Ruby 1.8, Ruby 1.9 and JRuby documentation for further details.
|
55
|
+
|
56
|
+
## Use cases
|
57
|
+
|
58
|
+
Trenza is an experiment and might not have any practical uses apart from that. But if you find one, let me know!
|
59
|
+
|
60
|
+
As for me, scripts with lots of I/O waiting (such as scripts that download files) seem a natural fit for `parallel` (see `examples/download.rb` for an example).
|
61
|
+
|
62
|
+
## Usage
|
63
|
+
|
64
|
+
Nothing special: install the gem, require it, call `lazy` or `parallel` when initializing your objects.
|
65
|
+
|
66
|
+
## License
|
67
|
+
|
68
|
+
Copyright © Sergio Gil, 2012
|
69
|
+
|
70
|
+
Licensed under the [MIT license](http://porras.mit-license.org/).
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'trenza'
|
3
|
+
|
4
|
+
|
5
|
+
class Download
|
6
|
+
def initialize(url)
|
7
|
+
@url = url
|
8
|
+
end
|
9
|
+
|
10
|
+
def size
|
11
|
+
open(@url).read.size
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
urls = [
|
16
|
+
'http://google.es',
|
17
|
+
'http://amazon.es',
|
18
|
+
'http://bebanjo.com'
|
19
|
+
]
|
20
|
+
|
21
|
+
puts urls.map { |url| Download.new(url).parallel.size }.reduce(:+)
|
22
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'trenza'
|
2
|
+
require 'benchmark'
|
3
|
+
|
4
|
+
class Calculator
|
5
|
+
def add(a, b)
|
6
|
+
result = a + b
|
7
|
+
sleep 0.01 * result
|
8
|
+
result
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def try(calc)
|
13
|
+
z = calc.add(10, 10)
|
14
|
+
a = calc.add(5, 7)
|
15
|
+
b = calc.add(3, 4)
|
16
|
+
c = calc.add(1, 2)
|
17
|
+
d = calc.add(3, 5)
|
18
|
+
f = calc.add(c, d)
|
19
|
+
e = calc.add(a, b)
|
20
|
+
g = calc.add(e, f)
|
21
|
+
g.to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
Benchmark.bm(10) do |bm|
|
26
|
+
bm.report("Regular") { try Calculator.new }
|
27
|
+
bm.report("Lazy") { try Calculator.new.lazy }
|
28
|
+
bm.report("Parallel") { try Calculator.new.parallel }
|
29
|
+
end
|
data/lib/trenza/lazy.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module Trenza
|
2
|
+
class Lazy
|
3
|
+
include BlankSlate
|
4
|
+
|
5
|
+
def initialize(object)
|
6
|
+
@object = object
|
7
|
+
end
|
8
|
+
|
9
|
+
def method_missing(meth, *args, &blk)
|
10
|
+
MethodCall.new do
|
11
|
+
@object.send meth, *args, &blk
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class MethodCall
|
16
|
+
include BlankSlate
|
17
|
+
|
18
|
+
def initialize(&block)
|
19
|
+
@block = block
|
20
|
+
end
|
21
|
+
|
22
|
+
def method_missing(meth, *args, &blk)
|
23
|
+
value.send meth, *args, &blk
|
24
|
+
end
|
25
|
+
|
26
|
+
def value
|
27
|
+
@value ||= @block.call
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Trenza
|
2
|
+
class Parallel
|
3
|
+
include BlankSlate
|
4
|
+
|
5
|
+
def initialize(object)
|
6
|
+
@object = object
|
7
|
+
end
|
8
|
+
|
9
|
+
def method_missing(meth, *args, &blk)
|
10
|
+
MethodCall.new do
|
11
|
+
@object.send meth, *args, &blk
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class MethodCall
|
16
|
+
include BlankSlate
|
17
|
+
|
18
|
+
def initialize(&block)
|
19
|
+
@thread = Thread.new(&block)
|
20
|
+
end
|
21
|
+
|
22
|
+
def method_missing(meth, *args, &blk)
|
23
|
+
@thread.value.send(meth, *args, &blk)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/trenza.rb
ADDED
metadata
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: trenza
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Sergio Gil
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-03-09 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description:
|
15
|
+
email: sgilperez@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- README.md
|
21
|
+
- lib/trenza/blank_slate.rb
|
22
|
+
- lib/trenza/lazy.rb
|
23
|
+
- lib/trenza/parallel.rb
|
24
|
+
- lib/trenza/proxy_builders.rb
|
25
|
+
- lib/trenza.rb
|
26
|
+
- examples/downloads.rb
|
27
|
+
- examples/slow_calculator.rb
|
28
|
+
homepage: http://github.com/porras/trenza
|
29
|
+
licenses: []
|
30
|
+
post_install_message:
|
31
|
+
rdoc_options: []
|
32
|
+
require_paths:
|
33
|
+
- lib
|
34
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
35
|
+
none: false
|
36
|
+
requirements:
|
37
|
+
- - ! '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
requirements: []
|
47
|
+
rubyforge_project:
|
48
|
+
rubygems_version: 1.8.10
|
49
|
+
signing_key:
|
50
|
+
specification_version: 3
|
51
|
+
summary: Adds parallelism to any object in a transparent way
|
52
|
+
test_files: []
|