threadify 0.0.3 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +22 -6
- data/README.rb +83 -0
- data/gemspec.rb +53 -26
- data/install.rb +0 -0
- data/lib/threadify.rb +7 -22
- data/threadify.gemspec +26 -0
- metadata +7 -8
- data/a.rb +0 -10
- data/gen_readme.rb +0 -32
- data/lib/threadify.rb.bak +0 -154
data/README
CHANGED
@@ -16,7 +16,7 @@ URI
|
|
16
16
|
http://rubyforge.org/projects/codeforpeople
|
17
17
|
|
18
18
|
SAMPLES
|
19
|
-
|
19
|
+
|
20
20
|
<========< sample/a.rb >========>
|
21
21
|
|
22
22
|
~ > cat sample/a.rb
|
@@ -66,10 +66,22 @@ SAMPLES
|
|
66
66
|
|
67
67
|
~ > ruby sample/a.rb
|
68
68
|
|
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
|
69
83
|
---
|
70
|
-
without threadify:
|
71
|
-
---
|
72
|
-
with threadify: 1.37899804115295
|
84
|
+
without threadify: 0.0373568534851074
|
73
85
|
|
74
86
|
|
75
87
|
<========< sample/b.rb >========>
|
@@ -113,16 +125,20 @@ SAMPLES
|
|
113
125
|
~ > ruby sample/b.rb
|
114
126
|
|
115
127
|
---
|
116
|
-
without threadify: 0.
|
128
|
+
without threadify: 0.00681805610656738
|
117
129
|
---
|
118
|
-
with threadify: 0.
|
130
|
+
with threadify: 0.57867693901062
|
119
131
|
---
|
120
132
|
:needle: 21844
|
121
133
|
:a: 21844
|
122
134
|
:b: 21844
|
123
135
|
|
124
136
|
|
137
|
+
|
125
138
|
HISTORY
|
139
|
+
1.0.0
|
140
|
+
- adjust threadify to yield objects exactly like Enumerable#each
|
141
|
+
|
126
142
|
0.0.3
|
127
143
|
- added ability to short-circuit the parallel processing, a.k.a to 'break'
|
128
144
|
from threadify
|
data/README.rb
ADDED
@@ -0,0 +1,83 @@
|
|
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
CHANGED
@@ -1,35 +1,62 @@
|
|
1
|
-
|
1
|
+
#! /usr/bin/env ruby
|
2
2
|
|
3
|
-
|
3
|
+
lib, version, *ignored = ARGV
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
unless lib
|
6
|
+
lib = File.basename(Dir.pwd)
|
7
|
+
end
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
14
17
|
|
15
|
-
|
16
|
-
spec.version = version
|
17
|
-
spec.platform = Gem::Platform::RUBY
|
18
|
-
spec.summary = lib
|
18
|
+
puts "### gemspec: #{ lib }-#{ version }"
|
19
19
|
|
20
|
-
|
21
|
-
spec.executables = shiteless[Dir::glob("bin/*")].map{|exe| File::basename exe}
|
22
|
-
|
23
|
-
spec.require_path = "lib"
|
20
|
+
$VERBOSE = nil
|
24
21
|
|
25
|
-
|
26
|
-
spec.test_suite_file = "test/#{ lib }.rb" if File::directory? "test"
|
27
|
-
#spec.add_dependency 'lib', '>= version'
|
22
|
+
shiteless = lambda{|list| list.delete_if{|file| file =~ %r/\.(git|svn|tmp|sw.|bak)$/}}
|
28
23
|
|
29
|
-
|
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")
|
30
28
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
spec.homepage = "http://codeforpeople.com/lib/ruby/#{ lib }/"
|
29
|
+
extensions = []
|
30
|
+
%w( Makefile configure extconf.rb rakefile Rakefile mkrf_conf ).each do |ext|
|
31
|
+
extensions << ext if File.exists?(ext)
|
35
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
CHANGED
File without changes
|
data/lib/threadify.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Threadify
|
2
|
-
VERSION = '0.0
|
2
|
+
VERSION = '1.0.0'
|
3
3
|
def Threadify.version() Threadify::VERSION end
|
4
4
|
|
5
5
|
require 'thread'
|
@@ -16,7 +16,7 @@ module Threadify
|
|
16
16
|
end
|
17
17
|
|
18
18
|
module Enumerable
|
19
|
-
def threadify
|
19
|
+
def threadify(opts = {}, &block)
|
20
20
|
# setup
|
21
21
|
#
|
22
22
|
opts = {:threads => opts} if Numeric === opts
|
@@ -29,13 +29,9 @@ module Enumerable
|
|
29
29
|
|
30
30
|
# produce jobs
|
31
31
|
#
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
each_with_index{|args, i| jobs[i % threads].push([args, i])}
|
37
|
-
threads.times{|i| jobs[i].push(done)}
|
38
|
-
#end
|
32
|
+
i = 0
|
33
|
+
each{|*args| jobs[i % threads].push([args, i]); i += 1}
|
34
|
+
threads.times{|i| jobs[i].push(done)}
|
39
35
|
|
40
36
|
# setup consumer list
|
41
37
|
#
|
@@ -107,17 +103,6 @@ module Enumerable
|
|
107
103
|
|
108
104
|
# collect the results and return them
|
109
105
|
#
|
110
|
-
=begin
|
111
|
-
jobs.push done
|
112
|
-
ret = []
|
113
|
-
while((job = jobs.pop) != done)
|
114
|
-
elem, i, value = job
|
115
|
-
ret[i] = value
|
116
|
-
end
|
117
|
-
ret
|
118
|
-
end
|
119
|
-
=end
|
120
|
-
|
121
106
|
ret = []
|
122
107
|
jobs.each do |results|
|
123
108
|
results.each do |result|
|
@@ -132,13 +117,13 @@ module Enumerable
|
|
132
117
|
end
|
133
118
|
|
134
119
|
class Thread
|
135
|
-
def Thread.ify
|
120
|
+
def Thread.ify(enumerable, *args, &block)
|
136
121
|
enumerable.send :threadify, *args, &block
|
137
122
|
end
|
138
123
|
end
|
139
124
|
|
140
125
|
class Object
|
141
|
-
def threadify!
|
126
|
+
def threadify!(*values)
|
142
127
|
throw :threadify, *values
|
143
128
|
end
|
144
129
|
end
|
data/threadify.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
### gemspec: threadify-1.0.0
|
2
|
+
|
3
|
+
Gem::Specification::new do |spec|
|
4
|
+
spec.name = "threadify"
|
5
|
+
spec.version = "1.0.0"
|
6
|
+
spec.platform = Gem::Platform::RUBY
|
7
|
+
spec.summary = "threadify"
|
8
|
+
|
9
|
+
spec.files = ["gemspec.rb", "install.rb", "lib", "lib/threadify.rb", "README", "README.rb", "sample", "sample/a.rb", "sample/b.rb", "threadify.gemspec"]
|
10
|
+
spec.executables = []
|
11
|
+
|
12
|
+
spec.require_path = "lib"
|
13
|
+
|
14
|
+
spec.has_rdoc = true
|
15
|
+
spec.test_files = nil
|
16
|
+
#spec.add_dependency 'lib', '>= version'
|
17
|
+
#spec.add_dependency 'fattr'
|
18
|
+
|
19
|
+
spec.extensions.push(*[])
|
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
|
26
|
+
|
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: 0.0
|
4
|
+
version: 1.0.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:
|
12
|
+
date: 2009-06-02 00:00:00 -06:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -22,19 +22,18 @@ extensions: []
|
|
22
22
|
extra_rdoc_files: []
|
23
23
|
|
24
24
|
files:
|
25
|
-
- a.rb
|
26
25
|
- gemspec.rb
|
27
|
-
- gen_readme.rb
|
28
26
|
- install.rb
|
29
27
|
- lib
|
30
28
|
- lib/threadify.rb
|
31
|
-
- lib/threadify.rb.bak
|
32
29
|
- README
|
30
|
+
- README.rb
|
33
31
|
- sample
|
34
32
|
- sample/a.rb
|
35
33
|
- sample/b.rb
|
36
|
-
|
37
|
-
|
34
|
+
- threadify.gemspec
|
35
|
+
has_rdoc: true
|
36
|
+
homepage: http://github.com/ahoward/threadify/tree/master
|
38
37
|
post_install_message:
|
39
38
|
rdoc_options: []
|
40
39
|
|
@@ -55,7 +54,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
55
54
|
requirements: []
|
56
55
|
|
57
56
|
rubyforge_project: codeforpeople
|
58
|
-
rubygems_version: 1.
|
57
|
+
rubygems_version: 1.3.1
|
59
58
|
signing_key:
|
60
59
|
specification_version: 2
|
61
60
|
summary: threadify
|
data/a.rb
DELETED
data/gen_readme.rb
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
require 'pathname'
|
2
|
-
|
3
|
-
$VERBOSE=nil
|
4
|
-
|
5
|
-
def indent s, n = 2
|
6
|
-
ws = ' ' * n
|
7
|
-
s.gsub %r/^/, ws
|
8
|
-
end
|
9
|
-
|
10
|
-
template = IO::read 'README.tmpl'
|
11
|
-
|
12
|
-
samples = ''
|
13
|
-
prompt = '~ > '
|
14
|
-
|
15
|
-
Dir['sample*/*'].sort.each do |sample|
|
16
|
-
samples << "\n" << " <========< #{ sample } >========>" << "\n\n"
|
17
|
-
|
18
|
-
cmd = "cat #{ sample }"
|
19
|
-
samples << indent(prompt + cmd, 2) << "\n\n"
|
20
|
-
samples << indent(`#{ cmd }`, 4) << "\n"
|
21
|
-
|
22
|
-
cmd = "ruby #{ sample }"
|
23
|
-
samples << indent(prompt + cmd, 2) << "\n\n"
|
24
|
-
|
25
|
-
cmd = "ruby -Ilib #{ sample }"
|
26
|
-
samples << indent(`#{ cmd } 2>&1`, 4) << "\n"
|
27
|
-
end
|
28
|
-
|
29
|
-
#samples.gsub! %r/^/, ' '
|
30
|
-
|
31
|
-
readme = template.gsub %r/^\s*@samples\s*$/, samples
|
32
|
-
print readme
|
data/lib/threadify.rb.bak
DELETED
@@ -1,154 +0,0 @@
|
|
1
|
-
module Threadify
|
2
|
-
VERSION = '0.0.3'
|
3
|
-
def Threadify.version() Threadify::VERSION end
|
4
|
-
|
5
|
-
require 'thread'
|
6
|
-
|
7
|
-
@threads = 8
|
8
|
-
@abort_on_exception = true
|
9
|
-
|
10
|
-
class << self
|
11
|
-
attr_accessor :threads
|
12
|
-
attr_accessor :abort_on_exception
|
13
|
-
end
|
14
|
-
|
15
|
-
class Error < ::StandardError; end
|
16
|
-
end
|
17
|
-
|
18
|
-
module Enumerable
|
19
|
-
def threadify opts = {}, &block
|
20
|
-
# setup
|
21
|
-
#
|
22
|
-
opts = {:threads => opts} if Numeric === opts
|
23
|
-
threads = Integer(opts[:threads] || opts['threads'] || Threadify.threads)
|
24
|
-
done = Object.new.freeze
|
25
|
-
nothing = done
|
26
|
-
jobs = Queue.new
|
27
|
-
top = Thread.current
|
28
|
-
|
29
|
-
# produce jobs
|
30
|
-
#
|
31
|
-
producer = Thread.new do
|
32
|
-
each_with_index{|args, i| jobs.push [args, i]}
|
33
|
-
threads.times{ jobs.push done}
|
34
|
-
end
|
35
|
-
|
36
|
-
# setup consumer list
|
37
|
-
#
|
38
|
-
consumers = Array.new threads
|
39
|
-
|
40
|
-
# setup support for short-circuit bailout via 'throw :threadify'
|
41
|
-
#
|
42
|
-
thrownv = Hash.new
|
43
|
-
thrownq = Queue.new
|
44
|
-
|
45
|
-
caught = false
|
46
|
-
|
47
|
-
catcher = Thread.new do
|
48
|
-
loop do
|
49
|
-
thrown = thrownq.pop
|
50
|
-
break if thrown == done
|
51
|
-
i, thrown = thrown
|
52
|
-
thrownv[i] = thrown
|
53
|
-
caught = true
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
# fire off the consumers
|
58
|
-
#
|
59
|
-
threads.times do |i|
|
60
|
-
consumers[i] =
|
61
|
-
Thread.new do
|
62
|
-
this = Thread.current
|
63
|
-
this.abort_on_exception = Threadify.abort_on_exception
|
64
|
-
|
65
|
-
job = nil
|
66
|
-
|
67
|
-
thrown =
|
68
|
-
catch(:threadify) do
|
69
|
-
loop{
|
70
|
-
break if caught
|
71
|
-
job = jobs.pop
|
72
|
-
break if job == done
|
73
|
-
args = job.first
|
74
|
-
jobs << (job << block.call(*args))
|
75
|
-
}
|
76
|
-
nothing
|
77
|
-
end
|
78
|
-
|
79
|
-
|
80
|
-
unless nothing == thrown
|
81
|
-
args, i = job
|
82
|
-
thrownq.push [i, thrown]
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
# wait for consumers to finish
|
88
|
-
#
|
89
|
-
consumers.map{|t| t.join}
|
90
|
-
|
91
|
-
# nuke the catcher
|
92
|
-
#
|
93
|
-
thrownq.push done
|
94
|
-
catcher.join
|
95
|
-
|
96
|
-
# iff something(s) was thrown return the one which would have been thrown
|
97
|
-
# earliest in non-parallel execution
|
98
|
-
#
|
99
|
-
unless thrownv.empty?
|
100
|
-
key = thrownv.keys.sort.first
|
101
|
-
return thrownv[key]
|
102
|
-
end
|
103
|
-
|
104
|
-
# collect the results and return them
|
105
|
-
#
|
106
|
-
jobs.push done
|
107
|
-
ret = []
|
108
|
-
while((job = jobs.pop) != done)
|
109
|
-
elem, i, value = job
|
110
|
-
ret[i] = value
|
111
|
-
end
|
112
|
-
ret
|
113
|
-
end
|
114
|
-
|
115
|
-
end
|
116
|
-
|
117
|
-
class Thread
|
118
|
-
def Thread.ify enumerable, *args, &block
|
119
|
-
enumerable.send :threadify, *args, &block
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
class Object
|
124
|
-
def threadify! *values
|
125
|
-
throw :threadify, *values
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
|
130
|
-
if __FILE__ == $0
|
131
|
-
require 'open-uri'
|
132
|
-
require 'yaml'
|
133
|
-
|
134
|
-
uris = %w( http://google.com http://yahoo.com http://rubyforge.org/ http://ruby-lang.org)
|
135
|
-
|
136
|
-
Thread.ify uris, :threads => 3 do |uri|
|
137
|
-
body = open(uri){|pipe| pipe.read}
|
138
|
-
y uri => body.size
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
|
143
|
-
__END__
|
144
|
-
|
145
|
-
sample output
|
146
|
-
|
147
|
-
---
|
148
|
-
http://yahoo.com: 9562
|
149
|
-
---
|
150
|
-
http://google.com: 6290
|
151
|
-
---
|
152
|
-
http://rubyforge.org/: 22352
|
153
|
-
---
|
154
|
-
http://ruby-lang.org: 9984
|