fizx-thread_pool 0.2.1 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,7 @@
1
+ 0.3.1
2
+ - rescue Thread errors, use Loggable to print backtraces
3
+ 0.3.0
4
+ - allow execute to take args, so we can reset the scope
1
5
  0.2.1
2
6
  - mutex in case Array#<< and Array#shift aren't atomic
3
7
  0.2.0
data/README CHANGED
@@ -1,3 +1,5 @@
1
+ This code is still pretty early, and not yet used in production. That said, I am interested in feedback. You can send me a message on GitHub's internal messaging system (http://github.com/inbox/new/fizx).
2
+
1
3
  A simple executor-style ThreadPool for Ruby (with tests, yay!)
2
4
 
3
5
  Usage:
@@ -6,4 +8,22 @@ Usage:
6
8
  require "thread_pool"
7
9
  pool = ThreadPool.new(threads = 10)
8
10
  pool.execute { puts "I'm writing from a thread" }
11
+ pool.join
12
+
13
+ It's often useful to make sure that the properties of Ruby's blocks don't bite you. The following code will usually print three nils, because n keeps changing.
14
+
15
+ pool = ThreadPool.new(threads = 10)
16
+ numbers = [1, 2, 3]
17
+ while n = numbers.shift
18
+ pool.execute { puts n.inspect }
19
+ end
20
+ pool.join
21
+
22
+ Passing arguments to execute avoids this. i.e.:
23
+
24
+ pool = ThreadPool.new(threads = 10)
25
+ numbers = [1, 2, 3]
26
+ while n = numbers.shift
27
+ pool.execute(n) {|local| puts local.inspect }
28
+ end
9
29
  pool.join
@@ -1,17 +1,30 @@
1
1
  # Hooray
2
2
  require "thread"
3
+ require "rubygems"
4
+ require "loggable"
5
+
3
6
  class ThreadPool
7
+ include Loggable
4
8
  class Executor
9
+ include Loggable
5
10
  attr_reader :active
6
11
 
7
12
  def initialize(queue, mutex)
8
13
  @thread = Thread.new do
9
14
  loop do
10
- mutex.synchronize { @block = queue.shift }
11
- if @block
15
+ mutex.synchronize { @tuple = queue.shift }
16
+ if @tuple
17
+ debug "Executor: processing #{@tuple.hash}"
18
+ args, block = @tuple
12
19
  @active = true
13
- @block.call
14
- @block.complete = true
20
+ begin
21
+ block.call(*args)
22
+ rescue Exception => e
23
+ error e.message
24
+ error e.backtrace.join("\n")
25
+ end
26
+ block.complete = true
27
+ debug "Executor: complete #{@tuple.hash}"
15
28
  else
16
29
  @active = false
17
30
  sleep 0.01
@@ -38,7 +51,7 @@ class ThreadPool
38
51
  end
39
52
 
40
53
  # Runs the block at some time in the near future
41
- def execute(&block)
54
+ def execute(*args, &block)
42
55
  init_completable(block)
43
56
 
44
57
  if @queue_limit > 0
@@ -46,13 +59,13 @@ class ThreadPool
46
59
  end
47
60
 
48
61
  @mutex.synchronize do
49
- @queue << block
62
+ @queue << [args, block]
50
63
  end
51
64
  end
52
65
 
53
66
  # Runs the block at some time in the near future, and blocks until complete
54
- def synchronous_execute(&block)
55
- execute(&block)
67
+ def synchronous_execute(*args, &block)
68
+ execute(*args, &block)
56
69
  sleep 0.01 until block.complete?
57
70
  end
58
71
 
@@ -30,6 +30,31 @@ class TestThreadPool < Test::Unit::TestCase
30
30
  assert_equal n - THREADS, @pool.waiting
31
31
  end
32
32
 
33
+ class A
34
+ def initialize(i)
35
+ @i = i
36
+ end
37
+ attr_reader :i
38
+ end
39
+
40
+ def test_context
41
+ @foo = []
42
+ @bar = (0...5).to_a
43
+ while c = @bar.shift
44
+ @pool.execute { @foo << c }
45
+ end
46
+ @pool.join
47
+ assert_equal [nil] * 5, @foo
48
+
49
+ @foo = []
50
+ @bar = (0...5).to_a
51
+ while c = @bar.shift
52
+ @pool.execute(c) {|n| @foo << n }
53
+ end
54
+ @pool.join
55
+ assert_equal (0...5).to_a, @foo
56
+ end
57
+
33
58
  def test_queue_limit
34
59
  n = 50
35
60
  @foo = 0
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fizx-thread_pool
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kyle Maxwell