thread_executor 1.0.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d5bde7f16838ab701a01d2ba70657239959a54a0
4
+ data.tar.gz: 2e809fb597ad664d6db40dd4d4eb9b4a4c83a857
5
+ SHA512:
6
+ metadata.gz: 809c32bc10a3e9eef3fa86bcf714ecfdb5b3222e262f4e14b07835e7107267ff0f5fb2aca372cb6892cbdca8e7bdd67e94e95a007dc4050d6f1083f0edcb90c3
7
+ data.tar.gz: 99c0696e26e27722809e10c09c1d438006d4c3a9ad93da0ddf2153473dd38e453e1f6713e2717f4d8e1ac6d687fe3c2db4b68c87796756588199f6c35e7949f1
data/Changelog ADDED
@@ -0,0 +1,8 @@
1
+ 2015-04-21 Sam Baskinger <basking2@yahoo.com>
2
+ * Extracting executor into independent package.
3
+
4
+ 2015-03-18 Sam Baskinger <basking2@yahoo.com>
5
+ * Adding concurrency with thread pool implementation.
6
+
7
+ Copyright 2014, 2015 Sam Baskinger <basking2@yahoo.com>
8
+
data/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # thread_executor
2
+ Ruby 2 thread executor library.
3
+
@@ -0,0 +1,40 @@
1
+ # Copyright (c) 2015, Sam Baskinger <basking2@yahoo.com>
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ #
7
+ # * Redistributions of source code must retain the above copyright notice, this
8
+ # list of conditions and the following disclaimer.
9
+ #
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ #
14
+ # * Neither the name of thread_executor nor the names of its
15
+ # contributors may be used to endorse or promote products derived from
16
+ # this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ require 'thread_executor/future'
30
+ require 'thread_executor/promise'
31
+ require 'thread_executor/executor'
32
+ require 'thread_executor/processor'
33
+
34
+ # A future/promise thread executor library.
35
+ #
36
+ # Start by checking out Executor.
37
+ #
38
+ module ThreadExecutor
39
+ end
40
+
@@ -0,0 +1,107 @@
1
+ # Copyright (c) 2015, Sam Baskinger <basking2@yahoo.com>
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ #
7
+ # * Redistributions of source code must retain the above copyright notice, this
8
+ # list of conditions and the following disclaimer.
9
+ #
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ #
14
+ # * Neither the name of thread_executor nor the names of its
15
+ # contributors may be used to endorse or promote products derived from
16
+ # this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ #
30
+ module ThreadExecutor
31
+
32
+ # A threaded executor.
33
+ #
34
+ # Procs can be given to this executor and are
35
+ # executed according to the availability of threads.
36
+ #
37
+ # = Use
38
+ #
39
+ # # Make an executor.
40
+ # executor = ThreadExecutor::Executor.new 10
41
+ #
42
+ # begin
43
+ #
44
+ # # Dispatch 100 jobs across the 10 threads.
45
+ # futures = 100.times.map { executor.call { do_long_running_work } }
46
+ #
47
+ # # Collect the results.
48
+ # results = futures.map { |future| future.value }
49
+ #
50
+ # ensure
51
+ # # Clean up the threads.
52
+ # executor.finish
53
+ # end
54
+ #
55
+ class Executor
56
+
57
+ # Build a new executor with +size+ Processor objects.
58
+ # The default size is 2.
59
+ #
60
+ # Each Processor contains a work queue and a running ruby Thread
61
+ # which will process the elements in the work queue.
62
+ #
63
+ # This Executor will insert elements into the work queue.
64
+ #
65
+ # Use of the Executor is not thread safe. If more than one thread
66
+ # submit work to Processor objects through this Executor, the
67
+ # Executor must be protected by a lock of some sort.
68
+ def initialize size=2
69
+ @processors = []
70
+
71
+ size.times do
72
+ @processors << Processor.new
73
+ end
74
+ end
75
+
76
+ # Enqueues the block in a processor queue with the fewest tasks.
77
+ #
78
+ # Returns a future for the result.
79
+ def call(&t)
80
+ min_processor = @processors[0]
81
+ min_size = min_processor.size
82
+ @processors.each do |p|
83
+ min_size2 = p.size
84
+ if min_size > min_size2
85
+ min_processor = p
86
+ min_size = min_size2
87
+ end
88
+ end
89
+
90
+ # Forward the user's block to the processor.
91
+ min_processor.call &t
92
+ end
93
+
94
+ # Sum of all queue depths.
95
+ def size
96
+ @processors.reduce(0) {|x,y| x + y.size}
97
+ end
98
+
99
+ # Shutdown and join all worker threads.
100
+ def finish
101
+ @processors.each do |p|
102
+ p.finish
103
+ end
104
+ end
105
+ end
106
+
107
+ end # module Sake
@@ -0,0 +1,51 @@
1
+ # Copyright (c) 2015, Sam Baskinger <basking2@yahoo.com>
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ #
7
+ # * Redistributions of source code must retain the above copyright notice, this
8
+ # list of conditions and the following disclaimer.
9
+ #
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ #
14
+ # * Neither the name of thread_executor nor the names of its
15
+ # contributors may be used to endorse or promote products derived from
16
+ # this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ module ThreadExecutor
30
+
31
+ # Proxies access to a Future object.
32
+ #
33
+ # This protects the user from doing the "wrong thing"
34
+ # with a Promise.
35
+ class Future
36
+ def initialize(promise)
37
+ @promise = promise
38
+ end
39
+
40
+ # Block until a value is ready.
41
+ #
42
+ # If an Exception was raised instead of producing a value
43
+ # it is rethrown.
44
+ #
45
+ # This call is proxied to Promise#value.
46
+ def value
47
+ @promise.value
48
+ end
49
+ end
50
+
51
+ end # module ThreadExecutor
@@ -0,0 +1,103 @@
1
+ # Copyright (c) 2015, Sam Baskinger <basking2@yahoo.com>
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ #
7
+ # * Redistributions of source code must retain the above copyright notice, this
8
+ # list of conditions and the following disclaimer.
9
+ #
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ #
14
+ # * Neither the name of thread_executor nor the names of its
15
+ # contributors may be used to endorse or promote products derived from
16
+ # this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ require 'thread'
30
+
31
+ module ThreadExecutor
32
+
33
+ # A processor is a Queue feeding a Thread.
34
+ class Processor
35
+
36
+ # Create Processor.
37
+ #
38
+ # This will create a new Queue and start a new ruby Thread.
39
+ #
40
+ # The created thread will block until work is inserted n the Queue
41
+ # using #call.
42
+ #
43
+ # To avoid leaking active threads you must call #finish to stop
44
+ # processing and join the Thread behind this object.
45
+ # Once this object is finished it may not be used again. It
46
+ # should be discarded.
47
+ #
48
+ # Typically the user should never create or use this class, but
49
+ # use an Executor, though there is nothing wrong in using this
50
+ # directly..
51
+ def initialize
52
+ @q = Queue.new
53
+ @t = Thread.new do
54
+ while true do
55
+ promise, task = @q.deq
56
+
57
+ # This is how we shut down the thread cleanly.
58
+ break if promise.nil? && task.nil?
59
+
60
+ begin
61
+ promise.value = task.call
62
+ rescue Exception => e
63
+ promise.exception = e
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ # Signal that the worker thread should exit.
70
+ #
71
+ # More precisely, this enqueues a stop request
72
+ # into the work queue, which, when encountered,
73
+ # causes the worker thread to cleanly exit and
74
+ # take no more work.
75
+ def shutdown
76
+ @q.enq [nil, nil]
77
+ end
78
+
79
+ # Adds a task, creates a Promise and returns a Future.
80
+ def call(&t)
81
+ p = Promise.new
82
+ @q.enq [ p, t ]
83
+ p.future
84
+ end
85
+
86
+ # Return the size of the work queue.
87
+ def size
88
+ @q.size
89
+ end
90
+
91
+ # Call #shutdown and join the thread.
92
+ #
93
+ # This will block until the thread is joined.
94
+ #
95
+ # When this returns this object is unusable and should
96
+ # be discarded.
97
+ def finish
98
+ shutdown
99
+ @t.join
100
+ end
101
+ end
102
+
103
+ end # module ThreadExecutor
@@ -0,0 +1,89 @@
1
+ # Copyright (c) 2015, Sam Baskinger <basking2@yahoo.com>
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ #
7
+ # * Redistributions of source code must retain the above copyright notice, this
8
+ # list of conditions and the following disclaimer.
9
+ #
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ #
14
+ # * Neither the name of thread_executor nor the names of its
15
+ # contributors may be used to endorse or promote products derived from
16
+ # this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ require 'thread_executor/future'
30
+
31
+ module ThreadExecutor
32
+
33
+ # A Promise is a container for a value that a Processor will compute.
34
+ #
35
+ # It contains locking objects to ensure that the value is communicated
36
+ # safely from the Processor 's Thread to user's Thread.
37
+ #
38
+ # A user typically never touches this object directly but
39
+ # examines the Future.
40
+ class Promise
41
+ attr_reader :value, :exception, :future
42
+
43
+ def initialize()
44
+ @value = nil
45
+ @exception = nil
46
+ @ready = false
47
+ @lock = Mutex.new
48
+ @cond = ConditionVariable.new
49
+ @no_result = true
50
+ @future = Future.new(self)
51
+ end
52
+
53
+ # Wait until this Promise is fulfilled and return the value
54
+ # If an exception was raised, it is reraised here.
55
+ def value
56
+ @lock.synchronize do
57
+
58
+ while ! @ready do
59
+ @cond.wait @lock
60
+ end
61
+
62
+ raise @exception if @exception
63
+
64
+ @value
65
+ end
66
+ end
67
+
68
+ def ready?
69
+ @ready
70
+ end
71
+
72
+ def value= v
73
+ @lock.synchronize do
74
+ @value = v
75
+ @ready = true
76
+ @cond.signal
77
+ end
78
+ end
79
+
80
+ def exception= e
81
+ @lock.synchronize do
82
+ @exception = e
83
+ @ready = true
84
+ @cond.signal
85
+ end
86
+ end
87
+ end
88
+
89
+ end # module ThreadExecutor
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: thread_executor
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Sam Baskinger
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-22 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: |2
14
+ Thread executor library.
15
+ email: basking2@yahoo.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files:
19
+ - README.md
20
+ - Changelog
21
+ files:
22
+ - Changelog
23
+ - README.md
24
+ - lib/thread_executor.rb
25
+ - lib/thread_executor/executor.rb
26
+ - lib/thread_executor/future.rb
27
+ - lib/thread_executor/processor.rb
28
+ - lib/thread_executor/promise.rb
29
+ homepage: https://github.com/basking2/thread_executor/
30
+ licenses:
31
+ - BSD
32
+ metadata: {}
33
+ post_install_message:
34
+ rdoc_options: []
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: 2.0.0
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ requirements: []
48
+ rubyforge_project:
49
+ rubygems_version: 2.2.2
50
+ signing_key:
51
+ specification_version: 4
52
+ summary: Thread executor library.
53
+ test_files: []