threadify 0.0.2 → 0.0.3

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 CHANGED
@@ -1,7 +1,6 @@
1
1
  NAME
2
2
  threadify.rb
3
3
 
4
-
5
4
  SYNOPSIS
6
5
  enumerable = %w( a b c d )
7
6
  enumerable.threadify(2){ 'process this block using two worker threads' }
@@ -68,7 +67,67 @@ SAMPLES
68
67
  ~ > ruby sample/a.rb
69
68
 
70
69
  ---
71
- without threadify: 7.41900205612183
70
+ without threadify: 3.75206303596497
72
71
  ---
73
- with threadify: 3.69886112213135
72
+ with threadify: 1.37899804115295
73
+
74
+
75
+ <========< sample/b.rb >========>
76
+
77
+ ~ > cat sample/b.rb
78
+
79
+ require 'yaml'
80
+
81
+ require 'rubygems'
82
+ require 'threadify'
83
+
84
+ size = Integer(ARGV.shift || (2 ** 15))
85
+
86
+ haystack = Array.new(size){|i| i}
87
+ needle = 2 * (size / 3)
88
+
89
+ a, b = 4, 2
90
+
91
+ time 'without threadify' do
92
+ a = haystack.each{|value| break value if value == needle}
93
+ end
94
+
95
+ time 'with threadify' do
96
+ b = haystack.threadify(16){|value| threadify! value if value == needle}
97
+ end
98
+
99
+ raise if a != b
100
+
101
+ y :a => a, :b => b, :needle => needle
102
+
103
+ BEGIN {
104
+ def time label
105
+ a = Time.now.to_f
106
+ yield
107
+ ensure
108
+ b = Time.now.to_f
109
+ y label => (b - a)
110
+ end
111
+ }
112
+
113
+ ~ > ruby sample/b.rb
114
+
115
+ ---
116
+ without threadify: 0.00630998611450195
117
+ ---
118
+ with threadify: 0.270262956619263
119
+ ---
120
+ :needle: 21844
121
+ :a: 21844
122
+ :b: 21844
123
+
124
+
125
+ HISTORY
126
+ 0.0.3
127
+ - added ability to short-circuit the parallel processing, a.k.a to 'break'
128
+ from threadify
74
129
 
130
+ 0.0.2
131
+ - don't use thread.exit, just let the thread die naturally
132
+ - add version to Threadify module
133
+ - comments ;-)
data/a.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'threadify'
2
+
3
+ a = Array.new(1024){|i| i}
4
+
5
+ value =
6
+ a.threadify do |i|
7
+ threadify! i if i == 512
8
+ end
9
+
10
+ p value
@@ -1,5 +1,5 @@
1
1
  module Threadify
2
- VERSION = '0.0.2'
2
+ VERSION = '0.0.3'
3
3
  def Threadify.version() Threadify::VERSION end
4
4
 
5
5
  require 'thread'
@@ -11,6 +11,8 @@ module Threadify
11
11
  attr_accessor :threads
12
12
  attr_accessor :abort_on_exception
13
13
  end
14
+
15
+ class Error < ::StandardError; end
14
16
  end
15
17
 
16
18
  module Enumerable
@@ -20,27 +22,69 @@ module Enumerable
20
22
  opts = {:threads => opts} if Numeric === opts
21
23
  threads = Integer(opts[:threads] || opts['threads'] || Threadify.threads)
22
24
  done = Object.new.freeze
23
- jobs = Queue.new
25
+ nothing = done
26
+ #jobs = Array.new(threads).map{ Queue.new }
27
+ jobs = Array.new(threads).map{ [] }
28
+ top = Thread.current
24
29
 
25
30
  # produce jobs
26
31
  #
27
- each_with_index{|elem, i| jobs.push [elem, i]}
28
- threads.times{ jobs.push done} # mark the end
32
+ #producer = Thread.new do
33
+ #this = Thread.current
34
+ #this.abort_on_exception = Threadify.abort_on_exception
35
+
36
+ each_with_index{|args, i| jobs[i % threads].push([args, i])}
37
+ threads.times{|i| jobs[i].push(done)}
38
+ #end
29
39
 
30
- # fire off consumers
40
+ # setup consumer list
31
41
  #
32
42
  consumers = Array.new threads
33
43
 
44
+ # setup support for short-circuit bailout via 'throw :threadify'
45
+ #
46
+ thrownv = Hash.new
47
+ thrownq = Queue.new
48
+
49
+ caught = false
50
+
51
+ catcher = Thread.new do
52
+ loop do
53
+ thrown = thrownq.pop
54
+ break if thrown == done
55
+ i, thrown = thrown
56
+ thrownv[i] = thrown
57
+ caught = true
58
+ end
59
+ end
60
+
61
+ # fire off the consumers
62
+ #
34
63
  threads.times do |i|
35
- consumers[i] = Thread.new do
64
+ consumers[i] = Thread.new(jobs[i]) do |jobsi|
36
65
  this = Thread.current
37
66
  this.abort_on_exception = Threadify.abort_on_exception
38
- loop{
39
- job = jobs.pop
40
- break if job == done
41
- args = job.first
42
- jobs << (job << block.call(*args))
43
- }
67
+
68
+ job = nil
69
+
70
+ thrown =
71
+ catch(:threadify) do
72
+ loop{
73
+ break if caught
74
+ #job = jobsi.pop
75
+ job = jobsi.shift
76
+ break if job == done
77
+ args = job.first
78
+ jobsi << (job << block.call(*args))
79
+ }
80
+ nothing
81
+ end
82
+
83
+
84
+ unless nothing == thrown
85
+ args, i = job
86
+ thrownq.push [i, thrown]
87
+ end
44
88
  end
45
89
  end
46
90
 
@@ -48,8 +92,22 @@ module Enumerable
48
92
  #
49
93
  consumers.map{|t| t.join}
50
94
 
95
+ # nuke the catcher
96
+ #
97
+ thrownq.push done
98
+ catcher.join
99
+
100
+ # iff something(s) was thrown return the one which would have been thrown
101
+ # earliest in non-parallel execution
102
+ #
103
+ unless thrownv.empty?
104
+ key = thrownv.keys.sort.first
105
+ return thrownv[key]
106
+ end
107
+
51
108
  # collect the results and return them
52
109
  #
110
+ =begin
53
111
  jobs.push done
54
112
  ret = []
55
113
  while((job = jobs.pop) != done)
@@ -58,6 +116,19 @@ module Enumerable
58
116
  end
59
117
  ret
60
118
  end
119
+ =end
120
+
121
+ ret = []
122
+ jobs.each do |results|
123
+ results.each do |result|
124
+ break if result == done
125
+ elem, i, value = result
126
+ ret[i] = value
127
+ end
128
+ end
129
+ ret
130
+ end
131
+
61
132
  end
62
133
 
63
134
  class Thread
@@ -66,6 +137,12 @@ class Thread
66
137
  end
67
138
  end
68
139
 
140
+ class Object
141
+ def threadify! *values
142
+ throw :threadify, *values
143
+ end
144
+ end
145
+
69
146
 
70
147
  if __FILE__ == $0
71
148
  require 'open-uri'
@@ -0,0 +1,154 @@
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
@@ -0,0 +1,33 @@
1
+ require 'yaml'
2
+
3
+ require 'rubygems'
4
+ require 'threadify'
5
+
6
+ size = Integer(ARGV.shift || (2 ** 15))
7
+
8
+ haystack = Array.new(size){|i| i}
9
+ needle = 2 * (size / 3)
10
+
11
+ a, b = 4, 2
12
+
13
+ time 'without threadify' do
14
+ a = haystack.each{|value| break value if value == needle}
15
+ end
16
+
17
+ time 'with threadify' do
18
+ b = haystack.threadify(16){|value| threadify! value if value == needle}
19
+ end
20
+
21
+ raise if a != b
22
+
23
+ y :a => a, :b => b, :needle => needle
24
+
25
+ BEGIN {
26
+ def time label
27
+ a = Time.now.to_f
28
+ yield
29
+ ensure
30
+ b = Time.now.to_f
31
+ y label => (b - a)
32
+ end
33
+ }
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.2
4
+ version: 0.0.3
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: 2008-07-01 00:00:00 -06:00
12
+ date: 2008-07-11 00:00:00 -06:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -22,15 +22,17 @@ extensions: []
22
22
  extra_rdoc_files: []
23
23
 
24
24
  files:
25
+ - a.rb
25
26
  - gemspec.rb
26
27
  - gen_readme.rb
27
28
  - install.rb
28
29
  - lib
29
30
  - lib/threadify.rb
31
+ - lib/threadify.rb.bak
30
32
  - README
31
33
  - sample
32
34
  - sample/a.rb
33
- - threadify-0.0.2.gem
35
+ - sample/b.rb
34
36
  has_rdoc: false
35
37
  homepage: http://codeforpeople.com/lib/ruby/threadify/
36
38
  post_install_message:
File without changes