threadify 0.0.3 → 1.0.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 +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
|