threadpool 0.0.1 → 0.0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +15 -1
- data/lib/threadpool.rb +19 -16
- data/threadpool.gemspec +1 -1
- metadata +1 -1
data/README.md
CHANGED
@@ -4,8 +4,22 @@ All the implementations I looked at were either buggy or wasted CPU resources
|
|
4
4
|
for no apparent reason, for example used a sleep of 0.01 seconds to then check for
|
5
5
|
readiness and stuff like this.
|
6
6
|
|
7
|
-
This implementation uses `IO.select` instead, there is no timed sleep, it just
|
7
|
+
This implementation uses `IO.select` instead, there is no timed sleep, it just stays
|
8
8
|
there waiting for input, which will then come from a `#wake_up` call that writes on a pipe.
|
9
9
|
|
10
10
|
`IO.select` should be present everywhere so this should be cross-platform and doesn't waste
|
11
11
|
CPU resources. Keep in mind that each worker uses 2 file descriptors (reading and writing pipe).
|
12
|
+
|
13
|
+
Example
|
14
|
+
-------
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
require 'threadpool'
|
18
|
+
|
19
|
+
pool = ThreadPool.new
|
20
|
+
pool.resize(4)
|
21
|
+
|
22
|
+
0.upto(10) { pool.process { sleep 2; puts 'lol' } }
|
23
|
+
```
|
24
|
+
|
25
|
+
You should get 4 lols every 2 seconds.
|
data/lib/threadpool.rb
CHANGED
@@ -36,19 +36,23 @@ class ThreadPool
|
|
36
36
|
class Worker
|
37
37
|
include Awakenable
|
38
38
|
|
39
|
-
def initialize (
|
40
|
-
@
|
41
|
-
@mutex
|
39
|
+
def initialize (pool)
|
40
|
+
@pool = pool
|
41
|
+
@mutex = Mutex.new
|
42
42
|
|
43
43
|
@thread = Thread.new {
|
44
44
|
loop do
|
45
45
|
if @block
|
46
|
-
|
46
|
+
begin
|
47
|
+
@block.call(*@args)
|
48
|
+
rescue Exception => e
|
49
|
+
@pool.raise(e)
|
50
|
+
end
|
47
51
|
|
48
52
|
@block = nil
|
49
53
|
@args = nil
|
50
54
|
|
51
|
-
@
|
55
|
+
@pool.wake_up
|
52
56
|
else
|
53
57
|
sleep
|
54
58
|
|
@@ -97,24 +101,27 @@ class ThreadPool
|
|
97
101
|
|
98
102
|
extend Forwardable
|
99
103
|
|
100
|
-
|
104
|
+
attr_reader :watcher, :size
|
105
|
+
def_delegators :@watcher, :sleep, :wake_up, :kill, :die?, :dead?, :join
|
106
|
+
def_delegators :@current, :raise
|
101
107
|
|
102
108
|
def initialize (size = 2)
|
103
109
|
@size = 0
|
104
110
|
@queue = Queue.new
|
105
111
|
@pool = []
|
106
|
-
@watcher = Worker.new
|
112
|
+
@watcher = Worker.new(self)
|
113
|
+
@current = Thread.current
|
107
114
|
|
108
115
|
@watcher.process {
|
109
116
|
loop do
|
110
|
-
|
111
|
-
next
|
117
|
+
sleep if @queue.empty?
|
118
|
+
next if @queue.empty?
|
112
119
|
|
113
120
|
begin
|
114
|
-
worker = @pool.find(&:available?) or
|
121
|
+
worker = @pool.find(&:available?) or sleep
|
115
122
|
end until worker
|
116
123
|
|
117
|
-
break if
|
124
|
+
break if die?
|
118
125
|
|
119
126
|
args, block = @queue.pop
|
120
127
|
|
@@ -127,16 +134,12 @@ class ThreadPool
|
|
127
134
|
resize(size)
|
128
135
|
end
|
129
136
|
|
130
|
-
def join
|
131
|
-
@watcher.join
|
132
|
-
end; alias wait join
|
133
|
-
|
134
137
|
def resize (size)
|
135
138
|
return if @size == size
|
136
139
|
|
137
140
|
if @size < size
|
138
141
|
1.upto(size - @size) {
|
139
|
-
@pool << Worker.new(
|
142
|
+
@pool << Worker.new(self)
|
140
143
|
}
|
141
144
|
else
|
142
145
|
1.upto(@size - size) {
|
data/threadpool.gemspec
CHANGED