threadify 1.0.0 → 1.1.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 +40 -43
- data/README.erb +38 -0
- data/lib/threadify.rb +14 -8
- data/rakefile +231 -0
- data/sample/a.rb +10 -15
- data/sample/b.rb +14 -6
- data/threadify.gemspec +21 -21
- metadata +4 -5
- data/README.rb +0 -83
- data/gemspec.rb +0 -62
- data/install.rb +0 -214
data/README
CHANGED
@@ -4,6 +4,7 @@ NAME
|
|
4
4
|
SYNOPSIS
|
5
5
|
enumerable = %w( a b c d )
|
6
6
|
enumerable.threadify(2){ 'process this block using two worker threads' }
|
7
|
+
enumerable.threadify(:each_slice, 4){ 'process each slice of 4 in a thread' }
|
7
8
|
|
8
9
|
DESCRIPTION
|
9
10
|
threadify.rb makes it stupid easy to process a bunch of data using 'n'
|
@@ -14,6 +15,7 @@ INSTALL
|
|
14
15
|
|
15
16
|
URI
|
16
17
|
http://rubyforge.org/projects/codeforpeople
|
18
|
+
http://github.com/ahoward/threadify/
|
17
19
|
|
18
20
|
SAMPLES
|
19
21
|
|
@@ -21,39 +23,34 @@ SAMPLES
|
|
21
23
|
|
22
24
|
~ > cat sample/a.rb
|
23
25
|
|
24
|
-
require 'open-uri'
|
25
|
-
require 'yaml'
|
26
|
-
|
27
|
-
require 'rubygems'
|
28
26
|
require 'threadify'
|
29
27
|
|
28
|
+
require 'open-uri'
|
29
|
+
require 'yaml'
|
30
30
|
|
31
31
|
uris =
|
32
32
|
%w(
|
33
|
+
http://codeforpeople.com
|
34
|
+
http://drawohara.com
|
35
|
+
http://twitter.com/drawohara
|
36
|
+
http://github.com/ahoward/threadify/
|
33
37
|
http://google.com
|
34
|
-
http://yahoo.com
|
35
38
|
http://rubyforge.org
|
36
39
|
http://ruby-lang.org
|
37
|
-
http://
|
38
|
-
http://drawohara.com
|
39
|
-
http://codeforpeople.com
|
40
|
+
http://hypem.com
|
40
41
|
)
|
41
42
|
|
43
|
+
curl = lambda{|url| open(url){|socket| socket.read}}
|
42
44
|
|
43
45
|
time 'without threadify' do
|
44
|
-
uris.each
|
45
|
-
body = open(uri){|pipe| pipe.read}
|
46
|
-
end
|
46
|
+
uris.each{|uri| curl[uri]}
|
47
47
|
end
|
48
48
|
|
49
49
|
|
50
50
|
time 'with threadify' do
|
51
|
-
uris.threadify
|
52
|
-
body = open(uri){|pipe| pipe.read}
|
53
|
-
end
|
51
|
+
uris.threadify(uris.size){|uri| curl[uri]}
|
54
52
|
end
|
55
53
|
|
56
|
-
|
57
54
|
BEGIN {
|
58
55
|
def time label
|
59
56
|
a = Time.now.to_f
|
@@ -66,34 +63,22 @@ SAMPLES
|
|
66
63
|
|
67
64
|
~ > ruby sample/a.rb
|
68
65
|
|
69
|
-
/opt/local/lib/ruby/1.8/net/http.rb:560:in `initialize': getaddrinfo: nodename nor servname provided, or not known (SocketError)
|
70
|
-
from /opt/local/lib/ruby/1.8/net/http.rb:560:in `open'
|
71
|
-
from /opt/local/lib/ruby/1.8/net/http.rb:560:in `connect'
|
72
|
-
from /opt/local/lib/ruby/1.8/timeout.rb:48:in `timeout'
|
73
|
-
from /opt/local/lib/ruby/1.8/timeout.rb:76:in `timeout'
|
74
|
-
from /opt/local/lib/ruby/1.8/net/http.rb:560:in `connect'
|
75
|
-
from /opt/local/lib/ruby/1.8/net/http.rb:553:in `do_start'
|
76
|
-
from /opt/local/lib/ruby/1.8/net/http.rb:542:in `start'
|
77
|
-
from /opt/local/lib/ruby/1.8/open-uri.rb:242:in `open_http'
|
78
|
-
... 8 levels...
|
79
|
-
from sample/a.rb:21:in `each'
|
80
|
-
from sample/a.rb:21
|
81
|
-
from sample/a.rb:37:in `time'
|
82
|
-
from sample/a.rb:20
|
83
66
|
---
|
84
|
-
without threadify:
|
67
|
+
without threadify: 12.6283850669861
|
68
|
+
---
|
69
|
+
with threadify: 1.93842315673828
|
85
70
|
|
86
71
|
|
87
72
|
<========< sample/b.rb >========>
|
88
73
|
|
89
74
|
~ > cat sample/b.rb
|
90
75
|
|
91
|
-
require 'yaml'
|
92
|
-
|
93
|
-
require 'rubygems'
|
94
76
|
require 'threadify'
|
95
77
|
|
96
|
-
|
78
|
+
require 'yaml'
|
79
|
+
|
80
|
+
#size = Integer(ARGV.shift || (2 ** 20))
|
81
|
+
size = 64
|
97
82
|
|
98
83
|
haystack = Array.new(size){|i| i}
|
99
84
|
needle = 2 * (size / 3)
|
@@ -101,11 +86,19 @@ SAMPLES
|
|
101
86
|
a, b = 4, 2
|
102
87
|
|
103
88
|
time 'without threadify' do
|
104
|
-
a =
|
89
|
+
a =
|
90
|
+
haystack.each do |value|
|
91
|
+
break value if value == needle
|
92
|
+
sleep(rand) # mimic work
|
93
|
+
end
|
105
94
|
end
|
106
95
|
|
107
96
|
time 'with threadify' do
|
108
|
-
b =
|
97
|
+
b =
|
98
|
+
haystack.threadify(:each_slice, size / 8) do |slice|
|
99
|
+
slice.each{|value| threadify! value if value == needle}
|
100
|
+
sleep(rand) # mimic work
|
101
|
+
end
|
109
102
|
end
|
110
103
|
|
111
104
|
raise if a != b
|
@@ -125,19 +118,23 @@ SAMPLES
|
|
125
118
|
~ > ruby sample/b.rb
|
126
119
|
|
127
120
|
---
|
128
|
-
without threadify:
|
121
|
+
without threadify: 22.8657438755035
|
129
122
|
---
|
130
|
-
with threadify: 0.
|
123
|
+
with threadify: 0.967911005020142
|
131
124
|
---
|
132
|
-
:needle:
|
133
|
-
:a:
|
134
|
-
:b:
|
125
|
+
:needle: 42
|
126
|
+
:a: 42
|
127
|
+
:b: 42
|
128
|
+
|
135
129
|
|
136
130
|
|
137
131
|
|
138
132
|
HISTORY
|
139
|
-
1.
|
140
|
-
-
|
133
|
+
1.1.0
|
134
|
+
- added ability to specify arbitrary iterator (not only each)
|
135
|
+
[0,1,2,3].threadify(:each_slice, 2){|ary| ary}
|
136
|
+
- update samples
|
137
|
+
- auto include enumerator
|
141
138
|
|
142
139
|
0.0.3
|
143
140
|
- added ability to short-circuit the parallel processing, a.k.a to 'break'
|
data/README.erb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
NAME
|
2
|
+
threadify.rb
|
3
|
+
|
4
|
+
SYNOPSIS
|
5
|
+
enumerable = %w( a b c d )
|
6
|
+
enumerable.threadify(2){ 'process this block using two worker threads' }
|
7
|
+
enumerable.threadify(:each_slice, 4){ 'process each slice of 4 in a thread' }
|
8
|
+
|
9
|
+
DESCRIPTION
|
10
|
+
threadify.rb makes it stupid easy to process a bunch of data using 'n'
|
11
|
+
worker threads
|
12
|
+
|
13
|
+
INSTALL
|
14
|
+
gem install threadify
|
15
|
+
|
16
|
+
URI
|
17
|
+
http://rubyforge.org/projects/codeforpeople
|
18
|
+
http://github.com/ahoward/threadify/
|
19
|
+
|
20
|
+
SAMPLES
|
21
|
+
<%= samples %>
|
22
|
+
|
23
|
+
|
24
|
+
HISTORY
|
25
|
+
1.1.0
|
26
|
+
- added ability to specify arbitrary iterator (not only each)
|
27
|
+
[0,1,2,3].threadify(:each_slice, 2){|ary| ary}
|
28
|
+
- update samples
|
29
|
+
- auto include enumerator
|
30
|
+
|
31
|
+
0.0.3
|
32
|
+
- added ability to short-circuit the parallel processing, a.k.a to 'break'
|
33
|
+
from threadify
|
34
|
+
|
35
|
+
0.0.2
|
36
|
+
- don't use thread.exit, just let the thread die naturally
|
37
|
+
- add version to Threadify module
|
38
|
+
- comments ;-)
|
data/lib/threadify.rb
CHANGED
@@ -1,36 +1,43 @@
|
|
1
1
|
module Threadify
|
2
|
-
VERSION = '1.
|
2
|
+
Threadify::VERSION = '1.1.0' unless defined?(Threadify::VERSION)
|
3
3
|
def Threadify.version() Threadify::VERSION end
|
4
4
|
|
5
5
|
require 'thread'
|
6
|
+
require 'enumerator'
|
6
7
|
|
7
8
|
@threads = 8
|
8
9
|
@abort_on_exception = true
|
10
|
+
@strategy = [:each]
|
9
11
|
|
10
12
|
class << self
|
11
13
|
attr_accessor :threads
|
12
14
|
attr_accessor :abort_on_exception
|
15
|
+
attr_accessor :strategy
|
13
16
|
end
|
14
17
|
|
15
18
|
class Error < ::StandardError; end
|
16
19
|
end
|
17
20
|
|
18
21
|
module Enumerable
|
19
|
-
def threadify(
|
22
|
+
def threadify(*args, &block)
|
20
23
|
# setup
|
21
24
|
#
|
22
|
-
opts =
|
23
|
-
|
25
|
+
opts = args.last.is_a?(Hash) ? args.pop : {}
|
26
|
+
opts.keys.each{|key| opts[key.to_s.to_sym] = opts.delete(key)}
|
27
|
+
opts[:threads] ||= (Numeric === args.first ? args.shift : Threadify.threads)
|
28
|
+
opts[:strategy] ||= (args.empty? ? Threadify.strategy : args)
|
29
|
+
|
30
|
+
threads = Integer(opts[:threads])
|
31
|
+
strategy = opts[:strategy]
|
24
32
|
done = Object.new.freeze
|
25
33
|
nothing = done
|
26
|
-
#jobs = Array.new(threads).map{ Queue.new }
|
27
34
|
jobs = Array.new(threads).map{ [] }
|
28
35
|
top = Thread.current
|
29
36
|
|
30
37
|
# produce jobs
|
31
38
|
#
|
32
39
|
i = 0
|
33
|
-
|
40
|
+
send(*strategy){|*args| jobs[i % threads].push([args, i]); i += 1}
|
34
41
|
threads.times{|i| jobs[i].push(done)}
|
35
42
|
|
36
43
|
# setup consumer list
|
@@ -67,7 +74,6 @@ module Enumerable
|
|
67
74
|
catch(:threadify) do
|
68
75
|
loop{
|
69
76
|
break if caught
|
70
|
-
#job = jobsi.pop
|
71
77
|
job = jobsi.shift
|
72
78
|
break if job == done
|
73
79
|
args = job.first
|
@@ -78,8 +84,8 @@ module Enumerable
|
|
78
84
|
|
79
85
|
|
80
86
|
unless nothing == thrown
|
81
|
-
args, i = job
|
82
87
|
thrownq.push [i, thrown]
|
88
|
+
args, i = job
|
83
89
|
end
|
84
90
|
end
|
85
91
|
end
|
data/rakefile
ADDED
@@ -0,0 +1,231 @@
|
|
1
|
+
|
2
|
+
This.rubyforge_project = 'codeforpeople'
|
3
|
+
This.author = "Ara T. Howard"
|
4
|
+
This.email = "ara.t.howard@gmail.com"
|
5
|
+
This.homepage = "http://github.com/ahoward/#{ This.lib }/tree/master"
|
6
|
+
|
7
|
+
|
8
|
+
task :default do
|
9
|
+
puts(Rake::Task.tasks.map{|task| task.name} - ['default'])
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
task :gemspec do
|
14
|
+
ignore_extensions = 'git', 'svn', 'tmp', /sw./, 'bak', 'gem'
|
15
|
+
ignore_directories = 'pkg'
|
16
|
+
|
17
|
+
shiteless =
|
18
|
+
lambda do |list|
|
19
|
+
list.delete_if do |entry|
|
20
|
+
next unless test(?e, entry)
|
21
|
+
extension = File.basename(entry).split(%r/[.]/).last
|
22
|
+
ignore_extensions.any?{|ext| ext === extension}
|
23
|
+
end
|
24
|
+
list.delete_if do |entry|
|
25
|
+
next unless test(?d, entry)
|
26
|
+
dirname = File.expand_path(entry)
|
27
|
+
ignore_directories.any?{|dir| File.expand_path(dir) == dirname}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
lib = This.lib
|
32
|
+
version = This.version
|
33
|
+
files = shiteless[Dir::glob("**/**")]
|
34
|
+
executables = shiteless[Dir::glob("bin/*")].map{|exe| File.basename(exe)}
|
35
|
+
has_rdoc = true #File.exist?('doc')
|
36
|
+
test_files = "test/#{ lib }.rb" if File.file?("test/#{ lib }.rb")
|
37
|
+
|
38
|
+
extensions = This.extensions
|
39
|
+
if extensions.nil?
|
40
|
+
%w( Makefile configure extconf.rb ).each do |ext|
|
41
|
+
extensions << ext if File.exists?(ext)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
extensions = [extensions].flatten.compact
|
45
|
+
|
46
|
+
template =
|
47
|
+
if test(?e, 'gemspec.erb')
|
48
|
+
Template{ IO.read('gemspec.erb') }
|
49
|
+
else
|
50
|
+
Template {
|
51
|
+
<<-__
|
52
|
+
## #{ lib }.gemspec
|
53
|
+
#
|
54
|
+
|
55
|
+
Gem::Specification::new do |spec|
|
56
|
+
spec.name = #{ lib.inspect }
|
57
|
+
spec.version = #{ version.inspect }
|
58
|
+
spec.platform = Gem::Platform::RUBY
|
59
|
+
spec.summary = #{ lib.inspect }
|
60
|
+
|
61
|
+
spec.files = #{ files.inspect }
|
62
|
+
spec.executables = #{ executables.inspect }
|
63
|
+
|
64
|
+
spec.require_path = "lib"
|
65
|
+
|
66
|
+
spec.has_rdoc = #{ has_rdoc.inspect }
|
67
|
+
spec.test_files = #{ test_files.inspect }
|
68
|
+
#spec.add_dependency 'lib', '>= version'
|
69
|
+
#spec.add_dependency 'fattr'
|
70
|
+
|
71
|
+
spec.extensions.push(*#{ extensions.inspect })
|
72
|
+
|
73
|
+
spec.rubyforge_project = #{ This.rubyforge_project.inspect }
|
74
|
+
spec.author = #{ This.author.inspect }
|
75
|
+
spec.email = #{ This.email.inspect }
|
76
|
+
spec.homepage = #{ This.homepage.inspect }
|
77
|
+
end
|
78
|
+
__
|
79
|
+
}
|
80
|
+
end
|
81
|
+
|
82
|
+
open("#{ lib }.gemspec", "w"){|fd| fd.puts template}
|
83
|
+
This.gemspec = "#{ lib }.gemspec"
|
84
|
+
end
|
85
|
+
|
86
|
+
task :gem => [:clean, :gemspec] do
|
87
|
+
#gem = File.join(This.pkgdir, "#{ lib }.gemspec")
|
88
|
+
#open("#{ This.pkgdir }/#{ lib }.gemspec", "w"){|fd| fd.puts template}
|
89
|
+
#before = Dir['*.gem']
|
90
|
+
#cmd = "gem build #{ This.lib }.gemspec"
|
91
|
+
#`#{ cmd } 2>&1`
|
92
|
+
#after = Dir['*.gem']
|
93
|
+
#gems = [after - before]
|
94
|
+
#p gems
|
95
|
+
|
96
|
+
Fu.mkdir_p This.pkgdir
|
97
|
+
Dir.chdir(This.pkgdir) do
|
98
|
+
cmd = "gem build ../#{ This.gemspec }"
|
99
|
+
`#{ cmd } 2>&1`
|
100
|
+
gem = Dir['*.gem'].first or 'abort no gem!'
|
101
|
+
This.gem = File.basename(gem)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
task :readme do
|
107
|
+
samples = ''
|
108
|
+
prompt = '~ > '
|
109
|
+
lib = This.lib
|
110
|
+
version = This.version
|
111
|
+
|
112
|
+
Dir['sample*/*'].sort.each do |sample|
|
113
|
+
samples << "\n" << " <========< #{ sample } >========>" << "\n\n"
|
114
|
+
|
115
|
+
cmd = "cat #{ sample }"
|
116
|
+
samples << Util.indent(prompt + cmd, 2) << "\n\n"
|
117
|
+
samples << Util.indent(`#{ cmd }`, 4) << "\n"
|
118
|
+
|
119
|
+
cmd = "ruby #{ sample }"
|
120
|
+
samples << Util.indent(prompt + cmd, 2) << "\n\n"
|
121
|
+
|
122
|
+
cmd = "ruby -e'STDOUT.sync=true; exec %(ruby -Ilib #{ sample })'"
|
123
|
+
samples << Util.indent(`#{ cmd } 2>&1`, 4) << "\n"
|
124
|
+
end
|
125
|
+
|
126
|
+
template =
|
127
|
+
if test(?e, 'readme.erb')
|
128
|
+
Template{ IO.read('readme.erb') }
|
129
|
+
else
|
130
|
+
Template {
|
131
|
+
<<-__
|
132
|
+
NAME
|
133
|
+
#{ lib }
|
134
|
+
|
135
|
+
DESCRIPTION
|
136
|
+
|
137
|
+
INSTALL
|
138
|
+
gem install #{ lib }
|
139
|
+
|
140
|
+
SAMPLES
|
141
|
+
#{ samples }
|
142
|
+
__
|
143
|
+
}
|
144
|
+
end
|
145
|
+
|
146
|
+
open("README", "w"){|fd| fd.puts template}
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
task :clean do
|
151
|
+
Dir[File.join(This.pkgdir, '**/**')].each{|entry| Fu.rm_rf(entry)}
|
152
|
+
end
|
153
|
+
|
154
|
+
|
155
|
+
task :release => [:clean, :gemspec, :gem] do
|
156
|
+
gems = Dir[File.join(This.pkgdir, '*.gem')].flatten
|
157
|
+
raise "which one? : #{ gems.inspect }" if gems.size > 1
|
158
|
+
raise "no gems?" if gems.size < 1
|
159
|
+
cmd = "rubyforge login && rubyforge add_release #{ This.rubyforge_project } #{ This.lib } #{ This.version } #{ This.pkgdir }/#{ This.gem }"
|
160
|
+
puts cmd
|
161
|
+
system cmd
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
|
166
|
+
|
167
|
+
|
168
|
+
BEGIN {
|
169
|
+
$VERBOSE = nil
|
170
|
+
|
171
|
+
require 'ostruct'
|
172
|
+
require 'erb'
|
173
|
+
require 'fileutils'
|
174
|
+
|
175
|
+
Fu = FileUtils
|
176
|
+
|
177
|
+
This = OpenStruct.new
|
178
|
+
|
179
|
+
This.file = File.expand_path(__FILE__)
|
180
|
+
This.dir = File.dirname(This.file)
|
181
|
+
This.pkgdir = File.join(This.dir, 'pkg')
|
182
|
+
|
183
|
+
lib = ENV['LIB']
|
184
|
+
unless lib
|
185
|
+
lib = File.basename(Dir.pwd)
|
186
|
+
end
|
187
|
+
This.lib = lib
|
188
|
+
|
189
|
+
version = ENV['VERSION']
|
190
|
+
unless version
|
191
|
+
name = lib.capitalize
|
192
|
+
require "./lib/#{ lib }"
|
193
|
+
version = eval(name).send(:version)
|
194
|
+
end
|
195
|
+
This.version = version
|
196
|
+
|
197
|
+
abort('no lib') unless This.lib
|
198
|
+
abort('no version') unless This.version
|
199
|
+
|
200
|
+
module Util
|
201
|
+
def indent(s, n = 2)
|
202
|
+
s = unindent(s)
|
203
|
+
ws = ' ' * n
|
204
|
+
s.gsub(%r/^/, ws)
|
205
|
+
end
|
206
|
+
|
207
|
+
def unindent(s)
|
208
|
+
indent = nil
|
209
|
+
s.each do |line|
|
210
|
+
next if line =~ %r/^\s*$/
|
211
|
+
indent = line[%r/^\s*/] and break
|
212
|
+
end
|
213
|
+
indent ? s.gsub(%r/^#{ indent }/, "") : s
|
214
|
+
end
|
215
|
+
extend self
|
216
|
+
end
|
217
|
+
|
218
|
+
class Template
|
219
|
+
def initialize(&block)
|
220
|
+
@block = block
|
221
|
+
@template = block.call.to_s
|
222
|
+
end
|
223
|
+
def expand(b=nil)
|
224
|
+
ERB.new(Util.unindent(@template)).result(b||@block)
|
225
|
+
end
|
226
|
+
alias_method 'to_s', 'expand'
|
227
|
+
end
|
228
|
+
def Template(*args, &block) Template.new(*args, &block) end
|
229
|
+
|
230
|
+
Dir.chdir(This.dir)
|
231
|
+
}
|
data/sample/a.rb
CHANGED
@@ -1,36 +1,31 @@
|
|
1
|
-
require 'open-uri'
|
2
|
-
require 'yaml'
|
3
|
-
|
4
|
-
require 'rubygems'
|
5
1
|
require 'threadify'
|
6
2
|
|
3
|
+
require 'open-uri'
|
4
|
+
require 'yaml'
|
7
5
|
|
8
6
|
uris =
|
9
7
|
%w(
|
8
|
+
http://codeforpeople.com
|
9
|
+
http://drawohara.com
|
10
|
+
http://twitter.com/drawohara
|
11
|
+
http://github.com/ahoward/threadify/
|
10
12
|
http://google.com
|
11
|
-
http://yahoo.com
|
12
13
|
http://rubyforge.org
|
13
14
|
http://ruby-lang.org
|
14
|
-
http://
|
15
|
-
http://drawohara.com
|
16
|
-
http://codeforpeople.com
|
15
|
+
http://hypem.com
|
17
16
|
)
|
18
17
|
|
18
|
+
curl = lambda{|url| open(url){|socket| socket.read}}
|
19
19
|
|
20
20
|
time 'without threadify' do
|
21
|
-
uris.each
|
22
|
-
body = open(uri){|pipe| pipe.read}
|
23
|
-
end
|
21
|
+
uris.each{|uri| curl[uri]}
|
24
22
|
end
|
25
23
|
|
26
24
|
|
27
25
|
time 'with threadify' do
|
28
|
-
uris.threadify
|
29
|
-
body = open(uri){|pipe| pipe.read}
|
30
|
-
end
|
26
|
+
uris.threadify(uris.size){|uri| curl[uri]}
|
31
27
|
end
|
32
28
|
|
33
|
-
|
34
29
|
BEGIN {
|
35
30
|
def time label
|
36
31
|
a = Time.now.to_f
|
data/sample/b.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
require 'yaml'
|
2
|
-
|
3
|
-
require 'rubygems'
|
4
1
|
require 'threadify'
|
5
2
|
|
6
|
-
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
#size = Integer(ARGV.shift || (2 ** 20))
|
6
|
+
size = 64
|
7
7
|
|
8
8
|
haystack = Array.new(size){|i| i}
|
9
9
|
needle = 2 * (size / 3)
|
@@ -11,11 +11,19 @@ needle = 2 * (size / 3)
|
|
11
11
|
a, b = 4, 2
|
12
12
|
|
13
13
|
time 'without threadify' do
|
14
|
-
a =
|
14
|
+
a =
|
15
|
+
haystack.each do |value|
|
16
|
+
break value if value == needle
|
17
|
+
sleep(rand) # mimic work
|
18
|
+
end
|
15
19
|
end
|
16
20
|
|
17
21
|
time 'with threadify' do
|
18
|
-
b =
|
22
|
+
b =
|
23
|
+
haystack.threadify(:each_slice, size / 8) do |slice|
|
24
|
+
slice.each{|value| threadify! value if value == needle}
|
25
|
+
sleep(rand) # mimic work
|
26
|
+
end
|
19
27
|
end
|
20
28
|
|
21
29
|
raise if a != b
|
data/threadify.gemspec
CHANGED
@@ -1,26 +1,26 @@
|
|
1
|
-
|
1
|
+
## threadify.gemspec
|
2
|
+
#
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
Gem::Specification::new do |spec|
|
5
|
+
spec.name = "threadify"
|
6
|
+
spec.version = "1.1.0"
|
7
|
+
spec.platform = Gem::Platform::RUBY
|
8
|
+
spec.summary = "threadify"
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
spec.files = ["lib", "lib/threadify.rb", "rakefile", "README", "README.erb", "sample", "sample/a.rb", "sample/b.rb", "threadify.gemspec"]
|
11
|
+
spec.executables = []
|
12
|
+
|
13
|
+
spec.require_path = "lib"
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
spec.has_rdoc = true
|
16
|
+
spec.test_files = nil
|
17
|
+
#spec.add_dependency 'lib', '>= version'
|
18
|
+
#spec.add_dependency 'fattr'
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
spec.rubyforge_project = 'codeforpeople'
|
22
|
-
spec.author = "Ara T. Howard"
|
23
|
-
spec.email = "ara.t.howard@gmail.com"
|
24
|
-
spec.homepage = "http://github.com/ahoward/threadify/tree/master"
|
25
|
-
end
|
20
|
+
spec.extensions.push(*[])
|
26
21
|
|
22
|
+
spec.rubyforge_project = "codeforpeople"
|
23
|
+
spec.author = "Ara T. Howard"
|
24
|
+
spec.email = "ara.t.howard@gmail.com"
|
25
|
+
spec.homepage = "http://github.com/ahoward/threadify/tree/master"
|
26
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: threadify
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ara T. Howard
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-06-
|
12
|
+
date: 2009-06-09 00:00:00 -06:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -22,12 +22,11 @@ extensions: []
|
|
22
22
|
extra_rdoc_files: []
|
23
23
|
|
24
24
|
files:
|
25
|
-
- gemspec.rb
|
26
|
-
- install.rb
|
27
25
|
- lib
|
28
26
|
- lib/threadify.rb
|
27
|
+
- rakefile
|
29
28
|
- README
|
30
|
-
- README.
|
29
|
+
- README.erb
|
31
30
|
- sample
|
32
31
|
- sample/a.rb
|
33
32
|
- sample/b.rb
|
data/README.rb
DELETED
@@ -1,83 +0,0 @@
|
|
1
|
-
#! /usr/bin/env ruby
|
2
|
-
|
3
|
-
template = <<-__
|
4
|
-
NAME
|
5
|
-
threadify.rb
|
6
|
-
|
7
|
-
SYNOPSIS
|
8
|
-
enumerable = %w( a b c d )
|
9
|
-
enumerable.threadify(2){ 'process this block using two worker threads' }
|
10
|
-
|
11
|
-
DESCRIPTION
|
12
|
-
threadify.rb makes it stupid easy to process a bunch of data using 'n'
|
13
|
-
worker threads
|
14
|
-
|
15
|
-
INSTALL
|
16
|
-
gem install threadify
|
17
|
-
|
18
|
-
URI
|
19
|
-
http://rubyforge.org/projects/codeforpeople
|
20
|
-
|
21
|
-
SAMPLES
|
22
|
-
<%= samples %>
|
23
|
-
|
24
|
-
HISTORY
|
25
|
-
1.0.0
|
26
|
-
- adjust threadify to yield objects exactly like Enumerable#each
|
27
|
-
|
28
|
-
0.0.3
|
29
|
-
- added ability to short-circuit the parallel processing, a.k.a to 'break'
|
30
|
-
from threadify
|
31
|
-
|
32
|
-
0.0.2
|
33
|
-
- don't use thread.exit, just let the thread die naturally
|
34
|
-
- add version to Threadify module
|
35
|
-
- comments ;-)
|
36
|
-
__
|
37
|
-
|
38
|
-
|
39
|
-
require 'erb'
|
40
|
-
require 'pathname'
|
41
|
-
|
42
|
-
$VERBOSE=nil
|
43
|
-
|
44
|
-
def indent(s, n = 2)
|
45
|
-
s = unindent(s)
|
46
|
-
ws = ' ' * n
|
47
|
-
s.gsub(%r/^/, ws)
|
48
|
-
end
|
49
|
-
|
50
|
-
def unindent(s)
|
51
|
-
indent = nil
|
52
|
-
s.each do |line|
|
53
|
-
next if line =~ %r/^\s*$/
|
54
|
-
indent = line[%r/^\s*/] and break
|
55
|
-
end
|
56
|
-
indent ? s.gsub(%r/^#{ indent }/, "") : s
|
57
|
-
end
|
58
|
-
|
59
|
-
samples = ''
|
60
|
-
prompt = '~ > '
|
61
|
-
|
62
|
-
Dir.chdir(File.dirname(__FILE__))
|
63
|
-
|
64
|
-
Dir['sample*/*'].sort.each do |sample|
|
65
|
-
samples << "\n" << " <========< #{ sample } >========>" << "\n\n"
|
66
|
-
|
67
|
-
cmd = "cat #{ sample }"
|
68
|
-
samples << indent(prompt + cmd, 2) << "\n\n"
|
69
|
-
samples << indent(`#{ cmd }`, 4) << "\n"
|
70
|
-
|
71
|
-
cmd = "ruby #{ sample }"
|
72
|
-
samples << indent(prompt + cmd, 2) << "\n\n"
|
73
|
-
|
74
|
-
cmd = "ruby -e'STDOUT.sync=true; exec %(ruby -Ilib #{ sample })'"
|
75
|
-
#cmd = "ruby -Ilib #{ sample }"
|
76
|
-
samples << indent(`#{ cmd } 2>&1`, 4) << "\n"
|
77
|
-
end
|
78
|
-
|
79
|
-
erb = ERB.new(unindent(template))
|
80
|
-
result = erb.result(binding)
|
81
|
-
#open('README', 'w'){|fd| fd.write result}
|
82
|
-
#puts unindent(result)
|
83
|
-
puts result
|
data/gemspec.rb
DELETED
@@ -1,62 +0,0 @@
|
|
1
|
-
#! /usr/bin/env ruby
|
2
|
-
|
3
|
-
lib, version, *ignored = ARGV
|
4
|
-
|
5
|
-
unless lib
|
6
|
-
lib = File.basename(Dir.pwd)
|
7
|
-
end
|
8
|
-
|
9
|
-
unless version
|
10
|
-
mod = lib.capitalize
|
11
|
-
require "./lib/#{ lib }"
|
12
|
-
version = eval(mod).send(:version)
|
13
|
-
end
|
14
|
-
|
15
|
-
abort('no lib') unless lib
|
16
|
-
abort('no version') unless version
|
17
|
-
|
18
|
-
puts "### gemspec: #{ lib }-#{ version }"
|
19
|
-
|
20
|
-
$VERBOSE = nil
|
21
|
-
|
22
|
-
shiteless = lambda{|list| list.delete_if{|file| file =~ %r/\.(git|svn|tmp|sw.|bak)$/}}
|
23
|
-
|
24
|
-
files = shiteless[Dir::glob("**/**")]
|
25
|
-
executables = shiteless[Dir::glob("bin/*")].map{|exe| File.basename(exe)}
|
26
|
-
has_rdoc = true #File.exist?('doc')
|
27
|
-
test_files = "test/#{ lib }.rb" if File.file?("test/#{ lib }.rb")
|
28
|
-
|
29
|
-
extensions = []
|
30
|
-
%w( Makefile configure extconf.rb rakefile Rakefile mkrf_conf ).each do |ext|
|
31
|
-
extensions << ext if File.exists?(ext)
|
32
|
-
end
|
33
|
-
|
34
|
-
template = <<-__
|
35
|
-
|
36
|
-
Gem::Specification::new do |spec|
|
37
|
-
spec.name = #{ lib.inspect }
|
38
|
-
spec.version = #{ version.inspect }
|
39
|
-
spec.platform = Gem::Platform::RUBY
|
40
|
-
spec.summary = #{ lib.inspect }
|
41
|
-
|
42
|
-
spec.files = #{ files.inspect }
|
43
|
-
spec.executables = #{ executables.inspect }
|
44
|
-
|
45
|
-
spec.require_path = "lib"
|
46
|
-
|
47
|
-
spec.has_rdoc = #{ has_rdoc.inspect }
|
48
|
-
spec.test_files = #{ test_files.inspect }
|
49
|
-
#spec.add_dependency 'lib', '>= version'
|
50
|
-
#spec.add_dependency 'fattr'
|
51
|
-
|
52
|
-
spec.extensions.push(*#{ extensions.inspect })
|
53
|
-
|
54
|
-
spec.rubyforge_project = 'codeforpeople'
|
55
|
-
spec.author = "Ara T. Howard"
|
56
|
-
spec.email = "ara.t.howard@gmail.com"
|
57
|
-
spec.homepage = "http://github.com/ahoward/#{ lib }/tree/master"
|
58
|
-
end
|
59
|
-
|
60
|
-
__
|
61
|
-
|
62
|
-
puts template
|
data/install.rb
DELETED
@@ -1,214 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
require 'rbconfig'
|
3
|
-
require 'find'
|
4
|
-
require 'ftools'
|
5
|
-
require 'tempfile'
|
6
|
-
include Config
|
7
|
-
|
8
|
-
LIBDIR = "lib"
|
9
|
-
LIBDIR_MODE = 0644
|
10
|
-
|
11
|
-
BINDIR = "bin"
|
12
|
-
BINDIR_MODE = 0755
|
13
|
-
|
14
|
-
|
15
|
-
$srcdir = CONFIG["srcdir"]
|
16
|
-
$version = CONFIG["MAJOR"]+"."+CONFIG["MINOR"]
|
17
|
-
$libdir = File.join(CONFIG["libdir"], "ruby", $version)
|
18
|
-
$archdir = File.join($libdir, CONFIG["arch"])
|
19
|
-
$site_libdir = $:.find {|x| x =~ /site_ruby$/}
|
20
|
-
$bindir = CONFIG["bindir"] || CONFIG['BINDIR']
|
21
|
-
$ruby_install_name = CONFIG['ruby_install_name'] || CONFIG['RUBY_INSTALL_NAME'] || 'ruby'
|
22
|
-
$ruby_ext = CONFIG['EXEEXT'] || ''
|
23
|
-
$ruby = File.join($bindir, ($ruby_install_name + $ruby_ext))
|
24
|
-
|
25
|
-
if !$site_libdir
|
26
|
-
$site_libdir = File.join($libdir, "site_ruby")
|
27
|
-
elsif $site_libdir !~ %r/#{Regexp.quote($version)}/
|
28
|
-
$site_libdir = File.join($site_libdir, $version)
|
29
|
-
end
|
30
|
-
|
31
|
-
def install_rb(srcdir=nil, destdir=nil, mode=nil, bin=nil)
|
32
|
-
#{{{
|
33
|
-
path = []
|
34
|
-
dir = []
|
35
|
-
Find.find(srcdir) do |f|
|
36
|
-
next unless FileTest.file?(f)
|
37
|
-
next if (f = f[srcdir.length+1..-1]) == nil
|
38
|
-
next if (/CVS$/ =~ File.dirname(f))
|
39
|
-
next if (/\.svn/ =~ File.dirname(f))
|
40
|
-
next if f =~ %r/\.lnk/
|
41
|
-
next if f =~ %r/\.svn/
|
42
|
-
next if f =~ %r/\.swp/
|
43
|
-
next if f =~ %r/\.svn/
|
44
|
-
path.push f
|
45
|
-
dir |= [File.dirname(f)]
|
46
|
-
end
|
47
|
-
for f in dir
|
48
|
-
next if f == "."
|
49
|
-
next if f == "CVS"
|
50
|
-
File::makedirs(File.join(destdir, f))
|
51
|
-
end
|
52
|
-
for f in path
|
53
|
-
next if (/\~$/ =~ f)
|
54
|
-
next if (/^\./ =~ File.basename(f))
|
55
|
-
unless bin
|
56
|
-
File::install(File.join(srcdir, f), File.join(destdir, f), mode, true)
|
57
|
-
else
|
58
|
-
from = File.join(srcdir, f)
|
59
|
-
to = File.join(destdir, f)
|
60
|
-
shebangify(from) do |sf|
|
61
|
-
$deferr.print from, " -> ", File::catname(from, to), "\n"
|
62
|
-
$deferr.printf "chmod %04o %s\n", mode, to
|
63
|
-
File::install(sf, to, mode, false)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
#}}}
|
68
|
-
end
|
69
|
-
def shebangify f
|
70
|
-
#{{{
|
71
|
-
open(f) do |fd|
|
72
|
-
buf = fd.read 42
|
73
|
-
if buf =~ %r/^\s*#\s*!.*ruby/o
|
74
|
-
ftmp = Tempfile::new("#{ $$ }_#{ File::basename(f) }")
|
75
|
-
begin
|
76
|
-
fd.rewind
|
77
|
-
ftmp.puts "#!#{ $ruby }"
|
78
|
-
while((buf = fd.read(8192)))
|
79
|
-
ftmp.write buf
|
80
|
-
end
|
81
|
-
ftmp.close
|
82
|
-
yield ftmp.path
|
83
|
-
ensure
|
84
|
-
ftmp.close!
|
85
|
-
end
|
86
|
-
else
|
87
|
-
yield f
|
88
|
-
end
|
89
|
-
end
|
90
|
-
#}}}
|
91
|
-
end
|
92
|
-
def ARGV.switch
|
93
|
-
#{{{
|
94
|
-
return nil if self.empty?
|
95
|
-
arg = self.shift
|
96
|
-
return nil if arg == '--'
|
97
|
-
if arg =~ /^-(.)(.*)/
|
98
|
-
return arg if $1 == '-'
|
99
|
-
raise 'unknown switch "-"' if $2.index('-')
|
100
|
-
self.unshift "-#{$2}" if $2.size > 0
|
101
|
-
"-#{$1}"
|
102
|
-
else
|
103
|
-
self.unshift arg
|
104
|
-
nil
|
105
|
-
end
|
106
|
-
#}}}
|
107
|
-
end
|
108
|
-
def ARGV.req_arg
|
109
|
-
#{{{
|
110
|
-
self.shift || raise('missing argument')
|
111
|
-
#}}}
|
112
|
-
end
|
113
|
-
def linkify d, linked = []
|
114
|
-
#--{{{
|
115
|
-
if test ?d, d
|
116
|
-
versioned = Dir[ File::join(d, "*-[0-9].[0-9].[0-9].rb") ]
|
117
|
-
versioned.each do |v|
|
118
|
-
src, dst = v, v.gsub(%r/\-[\d\.]+\.rb$/, '.rb')
|
119
|
-
lnk = nil
|
120
|
-
begin
|
121
|
-
if test ?l, dst
|
122
|
-
lnk = "#{ dst }.lnk"
|
123
|
-
puts "#{ dst } -> #{ lnk }"
|
124
|
-
File::rename dst, lnk
|
125
|
-
end
|
126
|
-
unless test ?e, dst
|
127
|
-
puts "#{ src } -> #{ dst }"
|
128
|
-
File::copy src, dst
|
129
|
-
linked << dst
|
130
|
-
end
|
131
|
-
ensure
|
132
|
-
if lnk
|
133
|
-
at_exit do
|
134
|
-
puts "#{ lnk } -> #{ dst }"
|
135
|
-
File::rename lnk, dst
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
linked
|
142
|
-
#--}}}
|
143
|
-
end
|
144
|
-
|
145
|
-
|
146
|
-
#
|
147
|
-
# main program
|
148
|
-
#
|
149
|
-
|
150
|
-
libdir = $site_libdir
|
151
|
-
bindir = $bindir
|
152
|
-
no_linkify = false
|
153
|
-
linked = nil
|
154
|
-
help = false
|
155
|
-
|
156
|
-
usage = <<-usage
|
157
|
-
#{ File::basename $0 }
|
158
|
-
-d, --destdir <destdir>
|
159
|
-
-l, --libdir <libdir>
|
160
|
-
-b, --bindir <bindir>
|
161
|
-
-r, --ruby <ruby>
|
162
|
-
-n, --no_linkify
|
163
|
-
-s, --sudo
|
164
|
-
-h, --help
|
165
|
-
usage
|
166
|
-
|
167
|
-
begin
|
168
|
-
while switch = ARGV.switch
|
169
|
-
case switch
|
170
|
-
when '-d', '--destdir'
|
171
|
-
libdir = ARGV.req_arg
|
172
|
-
when '-l', '--libdir'
|
173
|
-
libdir = ARGV.req_arg
|
174
|
-
when '-b', '--bindir'
|
175
|
-
bindir = ARGV.req_arg
|
176
|
-
when '-r', '--ruby'
|
177
|
-
$ruby = ARGV.req_arg
|
178
|
-
when '-n', '--no_linkify'
|
179
|
-
no_linkify = true
|
180
|
-
when '-s', '--sudo'
|
181
|
-
sudo = 'sudo'
|
182
|
-
when '-h', '--help'
|
183
|
-
help = true
|
184
|
-
else
|
185
|
-
raise "unknown switch #{switch.dump}"
|
186
|
-
end
|
187
|
-
end
|
188
|
-
rescue
|
189
|
-
STDERR.puts $!.to_s
|
190
|
-
STDERR.puts usage
|
191
|
-
exit 1
|
192
|
-
end
|
193
|
-
|
194
|
-
if help
|
195
|
-
STDOUT.puts usage
|
196
|
-
exit
|
197
|
-
end
|
198
|
-
|
199
|
-
system "#{ sudo } #{ $ruby } pre-install.rb" if test(?s, 'pre-install.rb')
|
200
|
-
|
201
|
-
unless no_linkify
|
202
|
-
linked = linkify('lib') + linkify('bin')
|
203
|
-
end
|
204
|
-
|
205
|
-
system "#{ $ruby } extconf.rb && make && #{ sudo } make install" if test(?s, 'extconf.rb')
|
206
|
-
|
207
|
-
install_rb(LIBDIR, libdir, LIBDIR_MODE)
|
208
|
-
install_rb(BINDIR, bindir, BINDIR_MODE, bin=true)
|
209
|
-
|
210
|
-
if linked
|
211
|
-
linked.each{|path| File::rm_f path}
|
212
|
-
end
|
213
|
-
|
214
|
-
system "#{ sudo } #{ $ruby } post-install.rb" if test(?s, 'post-install.rb')
|