thread-task 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 716712aca5f16f5f7cce6e2dd080b2bc8977ab6b52cc1a450ff26daa03490e75
4
+ data.tar.gz: 5426b3d682dcba73903471e2920cc37758dd76a6526a2f32c579a6907075d1a0
5
+ SHA512:
6
+ metadata.gz: e120a53671fea648459b54cb97616291515c7bdd27ceb9849e2010ba5e5f4da6f48d81cf922f45d25d9db0b7d619c83cd33ad92366216da2437d697fe2926ba2
7
+ data.tar.gz: 666026187d04520ef1a388db270a912e4a6b49f341549a719c1e4aa94a10960c68908c317879f0c158018355fa333558a92ed09e939348c69f3077f65c25ecaa
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ /.rspec_status
10
+ /vendor/
11
+ /var/
12
+ /log/
13
+ /Gemfile.*
14
+ *.bundle
15
+ *.so
16
+ *.o
17
+ *.a
18
+ *.pid
19
+ *.swp
20
+ *.log
21
+ *.log.*
22
+
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,73 @@
1
+
2
+ AllCops:
3
+ Exclude:
4
+ - '.*'
5
+ - '*'
6
+ - '*.gemspec'
7
+ - 'Gemfile*'
8
+ - 'bin/**'
9
+ - 'exe/**'
10
+ - 'config/**/*'
11
+ - 'spec/**/*'
12
+ - 'tmp/**/*'
13
+ - 'vendor/**/*'
14
+ TargetRubyVersion: 2.7
15
+
16
+ Layout/ExtraSpacing:
17
+ Enabled: false
18
+
19
+ Layout/SpaceAroundOperators:
20
+ Enabled: false
21
+
22
+ Layout/SpaceBeforeFirstArg:
23
+ Enabled: false
24
+
25
+ Layout/SpaceInsideParens:
26
+ Enabled: false
27
+
28
+ Layout/SpaceInsideArrayLiteralBrackets:
29
+ Enabled: false
30
+
31
+ Layout/SpaceInsideRangeLiteral:
32
+ Enabled: false
33
+
34
+ Layout/SpaceInsideReferenceBrackets:
35
+ Enabled: false
36
+
37
+ Layout/SpaceInsideStringInterpolation:
38
+ Enabled: false
39
+
40
+ Lint/AmbiguousBlockAssociation:
41
+ Enabled: false
42
+
43
+ Lint/EmptyWhen:
44
+ Enabled: false
45
+
46
+ Lint/ReturnInVoidContext:
47
+ Enabled: false
48
+
49
+ Lint/UselessAssignment:
50
+ Enabled: false
51
+
52
+ Metrics/BlockLength:
53
+ Enabled: false
54
+
55
+ Metrics/LineLength:
56
+ Enabled: false
57
+ Max: 120
58
+
59
+ Metrics/MethodLength:
60
+ Enabled: false
61
+
62
+ Style/Documentation:
63
+ Enabled: true
64
+
65
+ Style/FrozenStringLiteralComment:
66
+ Enabled: false
67
+
68
+ Style/NumericPredicate:
69
+ Enabled: false
70
+
71
+ Style/StringLiterals:
72
+ Enabled: false
73
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in thread-task.gemspec
4
+ gemspec
data/README.adoc ADDED
@@ -0,0 +1,224 @@
1
+ = Thread::Task
2
+
3
+ A wrapper library of Thread class for easily describing parallel processing.
4
+
5
+ == Features
6
+
7
+ * Thread::Task is a configuration that allows you to briefly describe the configuration often used in parallel processing.
8
+ * Thread::Task::Pool limits the number of parallel executions of Thread::Task.
9
+ * Runs only once within the specified timelimit.
10
+
11
+ == Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ [source,ruby]
16
+ ----
17
+ gem 'thread-task'
18
+ ----
19
+
20
+ And then execute:
21
+
22
+ $ bundle install
23
+
24
+ Or install it yourself as:
25
+
26
+ $ gem install thread-task
27
+ or
28
+ $ gem install -l thread-task-x.x.x.gem
29
+
30
+ == Usage
31
+
32
+ ::Thread::Task has alias ::Task.
33
+
34
+ === Start parallel execution, wait for completion and get result.
35
+
36
+ [source,ruby]
37
+ ----
38
+ require "thread/task"
39
+
40
+ task = Task.new do
41
+ sleep 2
42
+ Time.now
43
+ end
44
+ p task.value
45
+ ----
46
+
47
+ === Limit the max count of parallel executions.
48
+
49
+ [source,ruby]
50
+ ----
51
+ require "thread/task"
52
+
53
+ tasks = (0...10).map do |i|
54
+ p [i]
55
+ Task.new( i, count: 3 ) do |j|
56
+ p [" ->", j]
57
+ sleep( rand * 2 )
58
+ p ["<- ", j]
59
+ end
60
+ end
61
+
62
+ tasks.each(&:join)
63
+ ----
64
+
65
+ === Limit the max count of parallel executions with a Task::Pool.
66
+
67
+ [source,ruby]
68
+ ----
69
+ require "thread/task"
70
+
71
+ pool = Task::Pool.new(3)
72
+
73
+ tasks1 = (0...4).map do |i|
74
+ p [i]
75
+ Task.new( i, pool: pool ) do |j|
76
+ p [" ->", j]
77
+ sleep( rand * 2 )
78
+ p ["<- ", j]
79
+ end
80
+ end
81
+ tasks2 = (4...8).map do |i|
82
+ p [i]
83
+ Task.new( i, pool: pool ) do |j|
84
+ p [" ->", j]
85
+ sleep( rand * 2 )
86
+ p ["<- ", j]
87
+ end
88
+ end
89
+
90
+ tasks1.each(&:join)
91
+ tasks2.each(&:join)
92
+ ----
93
+
94
+ === Invoke the block only once at the beginning, and ignoring recalls within the time limit.
95
+
96
+ [source,ruby]
97
+ ----
98
+ require "thread/task"
99
+
100
+ tasks = (1..10).map do |i|
101
+ sleep 0.1
102
+ Task.once( i, guard:3 ) do |j|
103
+ p j
104
+ end
105
+ end
106
+
107
+ tasks.each(&:join)
108
+ ----
109
+
110
+ === When there is no recall within the time limit, invoke the block only once at the end.
111
+
112
+ [source,ruby]
113
+ ----
114
+ require "thread/task"
115
+
116
+ tasks = (1..10).map do |i|
117
+ sleep 0.1
118
+ Task.once( i, delay:3 ) do |j|
119
+ p j
120
+ end
121
+ end
122
+
123
+ tasks.each(&:join)
124
+ ----
125
+
126
+ == Reference
127
+
128
+ === Create a new Thread::Task.
129
+
130
+ [source,ruby]
131
+ ----
132
+ Thread::Task.new( *args, pool: nil, count: nil, &block )
133
+ ----
134
+
135
+ * Result:
136
+ ** Thread::Task object.
137
+
138
+ * Parameter:
139
+ ** args: Pass args as is to the block.
140
+ ** pool: Thread::Task::Pool object. (default: nil)
141
+ ** count: Max count of parallel executions. (default: nil)
142
+ ** block: callback action.
143
+
144
+ * Block Parameter:
145
+ ** args: Treat args as local variables specific to that thread.
146
+
147
+ === Wait for thread stop. Ignore thread exceptions.
148
+
149
+ [source,ruby]
150
+ ----
151
+ Thread::Task#join
152
+ ----
153
+
154
+ * Result:
155
+ ** nil
156
+
157
+ * Parameter:
158
+ ** none.
159
+
160
+ === Wait for the thread to stop and get the result. Detect the thread exception.
161
+
162
+ [source,ruby]
163
+ ----
164
+ Thread::Task#value
165
+ ----
166
+
167
+ * Result:
168
+ ** The execution result of the block.
169
+
170
+ * Parameter:
171
+ ** none.
172
+
173
+ === Cancel the execution of the thread.
174
+
175
+ [source,ruby]
176
+ ----
177
+ Thread::Task#cancel
178
+ ----
179
+
180
+ * Result:
181
+ ** nil.
182
+
183
+ * Parameter:
184
+ ** none.
185
+
186
+ === Create a new Thread::Pool.
187
+
188
+ [source,ruby]
189
+ ----
190
+ Thread::Task.once( *args, delay: nil, guard: nil, &block )
191
+ ----
192
+
193
+ * Result:
194
+ ** Thread::Task object.
195
+
196
+ * Parameter:
197
+ ** args: Pass args as is to the block.
198
+ ** delay: Wait for delay second before call block. (default: nil)
199
+ ** guard: Wait for guard second after call block. (default: nil)
200
+ ** ident: Task identifier. (default: nil )
201
+ ** block: callback action.
202
+
203
+ === Create a new Thread::Pool.
204
+
205
+ [source,ruby]
206
+ ----
207
+ Thread::Pool.new( count )
208
+ ----
209
+
210
+ * Result:
211
+ ** Thread::Pool object.
212
+
213
+ * Parameter:
214
+ ** count: Max count of parallel executions.
215
+
216
+ == Contributing
217
+
218
+ Bug reports and pull requests are welcome on GitHub at https://github.com/yorihara/thread-task.
219
+
220
+ == License
221
+
222
+ The gem is available as open source under the terms of the http://opensource.org/licenses/MIT[MIT License].
223
+
224
+ Copyright (c) yorihara <orihara.yasumi@gmail.com>
data/README.ja.adoc ADDED
@@ -0,0 +1,224 @@
1
+ = Thread::Task
2
+
3
+ 並列処理を簡単に記述するための Thread クラスのラッパーライブラリ.
4
+
5
+ == 特徴
6
+
7
+ * Thread::Task は並列処理でよく使う構成を簡潔に記述できるようにしたもの.
8
+ * Thread::Task::Pool は Thread::Task の並列実行数を制限する.
9
+ * 指定された制限時間内に一度だけ実行する.
10
+
11
+ == 導入
12
+
13
+ アプリの Gemfile にこの行を追加
14
+
15
+ [source,ruby]
16
+ ----
17
+ gem 'thread-task'
18
+ ----
19
+
20
+ それから実行
21
+
22
+ $ bundle install
23
+
24
+ または次のように手動で導入
25
+
26
+ $ gem install thread-task
27
+ or
28
+ $ gem install -l thread-task-x.x.x.gem
29
+
30
+ == 使い方
31
+
32
+ ::Thread::Task は ::Task の別名をもつ.
33
+
34
+ === 並列実行を開始して完了を待って結果を得る.
35
+
36
+ [source,ruby]
37
+ ----
38
+ require "thread/task"
39
+
40
+ task = Task.new do
41
+ sleep 2
42
+ Time.now
43
+ end
44
+ p task.value
45
+ ----
46
+
47
+ === 並列実行の最大数を制限する.
48
+
49
+ [source,ruby]
50
+ ----
51
+ require "thread/task"
52
+
53
+ tasks = (0...10).map do |i|
54
+ p [i]
55
+ Task.new( i, count: 3 ) do |j|
56
+ p [" ->", j]
57
+ sleep( rand * 2 )
58
+ p ["<- ", j]
59
+ end
60
+ end
61
+
62
+ tasks.each(&:join)
63
+ ----
64
+
65
+ === ひとつのプールで並列実行の最大数を制限する.
66
+
67
+ [source,ruby]
68
+ ----
69
+ require "thread/task"
70
+
71
+ pool = Task::Pool.new(3)
72
+
73
+ tasks1 = (0...4).map do |i|
74
+ p [i]
75
+ Task.new( i, pool: pool ) do |j|
76
+ p [" ->", j]
77
+ sleep( rand * 2 )
78
+ p ["<- ", j]
79
+ end
80
+ end
81
+ tasks2 = (4...8).map do |i|
82
+ p [i]
83
+ Task.new( i, pool: pool ) do |j|
84
+ p [" ->", j]
85
+ sleep( rand * 2 )
86
+ p ["<- ", j]
87
+ end
88
+ end
89
+
90
+ tasks1.each(&:join)
91
+ tasks2.each(&:join)
92
+ ----
93
+
94
+ === 最初に一度だけブロックを呼び出して、制限時間内の再呼び出しは無視する.
95
+
96
+ [source,ruby]
97
+ ----
98
+ require "thread/task"
99
+
100
+ tasks = (1..10).map do |i|
101
+ sleep 0.1
102
+ Task.once( i, guard:3 ) do |j|
103
+ p j
104
+ end
105
+ end
106
+
107
+ tasks.each(&:join)
108
+ ----
109
+
110
+ === 制限時間内に再呼び出しがないとき、最後に一度だけブロックを呼び出す.
111
+
112
+ [source,ruby]
113
+ ----
114
+ require "thread/task"
115
+
116
+ tasks = (1..10).map do |i|
117
+ sleep 0.1
118
+ Task.once( i, delay:3 ) do |j|
119
+ p j
120
+ end
121
+ end
122
+
123
+ tasks.each(&:join)
124
+ ----
125
+
126
+ == リファレンス
127
+
128
+ === 新たな Thread::Task を作成する.
129
+
130
+ [source,ruby]
131
+ ----
132
+ Thread::Task.new( *args, pool: nil, count: nil, &block )
133
+ ----
134
+
135
+ * Result:
136
+ ** Thread::Task オブジェクト.
137
+
138
+ * Parameter:
139
+ ** args: args はそのままブロックに渡す.
140
+ ** pool: Thread::Task::Pool オブジェクト. (default: nil)
141
+ ** count: 並列実行の最大数. (default: nil)
142
+ ** block: コールバック動作.
143
+
144
+ * Block Parameter:
145
+ ** args: args をそのスレッド固有のローカル変数として扱う.
146
+
147
+ === スレッド停止を待つ. スレッドの例外を無視する.
148
+
149
+ [source,ruby]
150
+ ----
151
+ Thread::Task#join
152
+ ----
153
+
154
+ * Result:
155
+ ** nil
156
+
157
+ * Parameter:
158
+ ** なし.
159
+
160
+ === スレッド停止を待って結果を得る. スレッドの例外を検出する.
161
+
162
+ [source,ruby]
163
+ ----
164
+ Thread::Task#value
165
+ ----
166
+
167
+ * Result:
168
+ ** ブロックの実行結果.
169
+
170
+ * Parameter:
171
+ ** なし.
172
+
173
+ === スレッドの実行を取り消す.
174
+
175
+ [source,ruby]
176
+ ----
177
+ Thread::Task#cancel
178
+ ----
179
+
180
+ * Result:
181
+ ** nil.
182
+
183
+ * Parameter:
184
+ ** なし.
185
+
186
+ === 短時間のうちに同じ行が再び呼び出された際に、一度だけ実行する.
187
+
188
+ [source,ruby]
189
+ ----
190
+ Thread::Task.once( *args, delay: nil, guard: nil, ident: nil, &block )
191
+ ----
192
+
193
+ * Result:
194
+ ** Thread::Task オブジェクト.
195
+
196
+ * Parameter:
197
+ ** args: args はそのままブロックに渡す.
198
+ ** delay: 実行前に待機する秒数. (default: nil)
199
+ ** guard: 実行後に保護する秒数. (default: nil)
200
+ ** ident: タスク識別子. (default: nil )
201
+ ** block: コールバック動作.
202
+
203
+ === 新たな Thread::Pool を作成する.
204
+
205
+ [source,ruby]
206
+ ----
207
+ Thread::Pool.new( count )
208
+ ----
209
+
210
+ * Result:
211
+ ** Thread::Pool オブジェクト.
212
+
213
+ * Parameter:
214
+ ** count: 並列実行の最大数.
215
+
216
+ == 貢献
217
+
218
+ 不具合報告とプルリクエストは GitHub https://github.com/yorihara/thread-task まで.
219
+
220
+ == ライセンス
221
+
222
+ この Gem は、 http://opensource.org/licenses/MIT[MITライセンス] の条件に基づいてオープンソースとして入手できる.
223
+
224
+ Copyright (c) yorihara <orihara.yasumi@gmail.com>
data/Rakefile ADDED
@@ -0,0 +1,96 @@
1
+ require "bundler/gem_helper"
2
+ require "bundler/gem_tasks"
3
+ require "rspec/core/rake_task"
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
8
+
9
+ class Bundler::GemHelper
10
+
11
+ def git_archive( dir = "../zip" )
12
+ FileUtils.mkdir_p dir
13
+ dest_path = File.join(dir, "#{name}-#{version}.zip")
14
+ cmnd = "git archive --format zip --prefix=#{name}/ HEAD > #{dest_path}"
15
+
16
+ out, code = sh_with_status( cmnd )
17
+ raise "Couldn't archive gem," unless code == 0
18
+
19
+ Bundler.ui.confirm "#{name} #{version} archived to #{dest_path}."
20
+ end
21
+
22
+ def git_push
23
+ ver = version.to_s
24
+
25
+ cmnd = "git push origin #{ver} "
26
+ out, code = sh_with_status( cmnd )
27
+ raise "Couldn't git push origin." unless code == 0
28
+
29
+ cmnd = "git push "
30
+ out, code = sh_with_status( cmnd )
31
+ raise "Couldn't git push." unless code == 0
32
+
33
+ Bundler.ui.confirm "Git Push #{ver}."
34
+ end
35
+
36
+ def update_version( new_version )
37
+ version_filename = %x[ find . -type f -name "version.rb" | grep -v vendor | head -1 ].chomp
38
+ version_pathname = File.expand_path( version_filename )
39
+ lines = File.open( version_pathname ).read
40
+ lines = lines.gsub( /VERSION\s*=\s*\"\d+\.\d+\.\d+\"/, "VERSION = \"#{new_version}\"" )
41
+ File.open( version_pathname, "w" ) do |file|
42
+ file.write( lines )
43
+ end
44
+
45
+ cmnd = "git add #{version_pathname} "
46
+ out, code = sh_with_status( cmnd )
47
+ raise "Couldn't git add," unless code == 0
48
+
49
+ cmnd = "git commit -m '#{new_version}' "
50
+ out, code = sh_with_status( cmnd )
51
+ raise "Couldn't git commit." unless code == 0
52
+
53
+ cmnd = "git tag #{new_version} "
54
+ out, code = sh_with_status( cmnd )
55
+ raise "Couldn't git tag." unless code == 0
56
+
57
+ Bundler.ui.confirm "Update Tags to #{new_version}."
58
+ end
59
+
60
+ end
61
+
62
+ Bundler::GemHelper.new(Dir.pwd).instance_eval do
63
+
64
+ desc "Archive #{name}-#{version}.zip from repository"
65
+ task 'zip' do
66
+ git_archive
67
+ end
68
+
69
+ desc "Git Push"
70
+ task 'push' do
71
+ git_push
72
+ end
73
+
74
+ desc "Update Version Tiny"
75
+ task 'tiny' do
76
+ major, minor, tiny = version.to_s.split('.')
77
+ new_version = [major, minor, tiny.to_i + 1].join('.')
78
+ update_version( new_version )
79
+ end
80
+
81
+ desc "Update Version Minor"
82
+ task 'minor' do
83
+ major, minor, tiny = version.to_s.split('.')
84
+ new_version = [major, minor.to_i + 1, 0].join('.')
85
+ update_version( new_version )
86
+ end
87
+
88
+ desc "Update Version Major"
89
+ task 'major' do
90
+ major, minor, tiny = version.to_s.split('.')
91
+ new_version = [major.to_i + 1, 0, 0].join('.')
92
+ update_version( new_version )
93
+ end
94
+
95
+ end
96
+
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "thread/task"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,5 @@
1
+ require "thread/task/version"
2
+ require "thread/task/base"
3
+
4
+ ::Task = ::Thread::Task unless defined?(::Task)
5
+
@@ -0,0 +1,139 @@
1
+ require "monitor"
2
+
3
+ class ::Thread
4
+ class Task
5
+
6
+ class Pool
7
+ attr_reader :rest
8
+
9
+ def initialize( size )
10
+ @rest = size
11
+ @monitor = Monitor.new
12
+ @lock_cond = @monitor.new_cond
13
+ end
14
+
15
+ def acquire
16
+ @monitor.synchronize do
17
+ @lock_cond.wait_while{ @rest == 0 }
18
+ @rest -= 1
19
+ end
20
+ end
21
+
22
+ def release
23
+ @monitor.synchronize do
24
+ @rest += 1
25
+ @lock_cond.signal
26
+ end
27
+ end
28
+ end
29
+
30
+ @@pool = ::Hash.new
31
+
32
+ def initialize( *args, pool: nil, count: nil, report_on_exception: false, &block )
33
+ raise ::ArgumentError, "block required." if block.nil?
34
+
35
+ if pool.nil? and count.nil?
36
+ @thread = ::Thread.start( args ) do |args_|
37
+ ::Thread.current.report_on_exception = report_on_exception
38
+ block.call( *args_ )
39
+ end
40
+
41
+ elsif pool and pool.is_a?(::Thread::Task::Pool)
42
+ @thread = ::Thread.start( args ) do |args_|
43
+ ::Thread.current.report_on_exception = report_on_exception
44
+ pool.acquire
45
+ begin
46
+ block.call( *args_ )
47
+ ensure
48
+ pool.release
49
+ end
50
+ end
51
+
52
+ elsif count and count.is_a? ::Integer and count > 0
53
+ key = caller[1]
54
+ unless ( pool = @@pool[key] )
55
+ pool = ::Thread::Task::Pool.new( count )
56
+ @@pool[key] = pool
57
+ end
58
+
59
+ @thread = ::Thread.start( args ) do |args_|
60
+ ::Thread.current.report_on_exception = report_on_exception
61
+ pool.acquire
62
+ begin
63
+ block.call( *args_ )
64
+ ensure
65
+ pool.release
66
+ end
67
+ end
68
+
69
+ else
70
+ raise ::ArgumentError, "Nil or size of Thread::Task::Pool object expected."
71
+
72
+ end
73
+ end
74
+
75
+ def join
76
+ @thread.join
77
+ end
78
+
79
+ def value
80
+ @thread.value
81
+ end
82
+
83
+ def cancel
84
+ @thread.kill
85
+ nil
86
+ end
87
+
88
+ class Counter
89
+ def initialize
90
+ @count = 0
91
+ @mutex = Mutex.new
92
+ end
93
+
94
+ def incr
95
+ @mutex.synchronize do
96
+ @count += 1
97
+ end
98
+ end
99
+
100
+ def decr
101
+ @mutex.synchronize do
102
+ @count -= 1 if @count > 0
103
+ @count
104
+ end
105
+ end
106
+
107
+ def reset
108
+ @mutex.synchronize do
109
+ @count = 0
110
+ end
111
+ end
112
+ end
113
+
114
+ @@counter = ::Hash.new{|h,k| h[k] = Counter.new }
115
+
116
+ def Task.once( *args, delay: nil, guard: nil, ident: nil, &block )
117
+ key = ( ident || caller[0] ).to_s
118
+ if delay and delay.is_a? ::Numeric and delay > 0
119
+ @@counter[key].incr
120
+ ::Thread::Task.new( key ) do |key_|
121
+ ::Kernel.sleep delay
122
+ count = @@counter[key_].decr
123
+ block.call( *args ) if count == 0
124
+ end
125
+ elsif guard and guard.is_a? ::Numeric and guard > 0
126
+ count = @@counter[key].incr
127
+ block.call( *args ) if count == 1
128
+ ::Thread::Task.new( key ) do |key_|
129
+ ::Kernel.sleep guard
130
+ @@counter[key_].decr
131
+ end
132
+ else
133
+ raise ::ArgumentError, "delay or guard time expected."
134
+ end
135
+ end
136
+
137
+ end
138
+ end
139
+
@@ -0,0 +1,5 @@
1
+ class ::Thread
2
+ class Task
3
+ VERSION = "2.0.0"
4
+ end
5
+ end
data/sample/base_1.rb ADDED
@@ -0,0 +1,8 @@
1
+ require "thread/task"
2
+
3
+ task = Task.new do
4
+ sleep 2
5
+ Time.now
6
+ end
7
+ p task.value
8
+
@@ -0,0 +1,12 @@
1
+ require "thread/task"
2
+
3
+ tasks = (0...8).map do |i|
4
+ Task.new( i, count:3 ) do |j|
5
+ p [" ->", j]
6
+ sleep rand*2
7
+ p ["<- ", j]
8
+ end
9
+ end
10
+
11
+ tasks.each(&:join)
12
+
@@ -0,0 +1,22 @@
1
+ require "thread/task"
2
+
3
+ pool = Task::Pool.new( 3 )
4
+
5
+ tasks1 = (0...4).map do |i|
6
+ Task.new( i, pool: pool ) do |j|
7
+ p [" ->", j]
8
+ sleep(rand*2)
9
+ p ["<- ", j]
10
+ end
11
+ end
12
+ tasks2 = (4...8).map do |i|
13
+ Task.new( i, pool: pool ) do |j|
14
+ p [" ->", j]
15
+ sleep(rand*2)
16
+ p ["<- ", j]
17
+ end
18
+ end
19
+
20
+ tasks1.each(&:join)
21
+ tasks2.each(&:join)
22
+
@@ -0,0 +1,10 @@
1
+ require "thread/task"
2
+
3
+ tasks = (1...8).map do |i|
4
+ sleep 0.1
5
+ Task.once( i, delay:3 ) do |j|
6
+ p j
7
+ end
8
+ end
9
+
10
+ tasks.each(&:join)
@@ -0,0 +1,20 @@
1
+ require "thread/task"
2
+
3
+ ident = "foobar"
4
+
5
+ tasks1 = (1...4).map do |i|
6
+ sleep 0.1
7
+ Task.once( i, delay:3, ident: ident ) do |j|
8
+ p j
9
+ end
10
+ end
11
+ tasks2 = (4...8).map do |i|
12
+ sleep 0.1
13
+ Task.once( i, delay:3, ident: ident ) do |j|
14
+ p j
15
+ end
16
+ end
17
+
18
+ tasks1.each(&:join)
19
+ tasks2.each(&:join)
20
+
@@ -0,0 +1,10 @@
1
+ require "thread/task"
2
+
3
+ tasks = (1...8).map do |i|
4
+ sleep 0.1
5
+ Task.once( i, guard:3 ) do |j|
6
+ p j
7
+ end
8
+ end
9
+
10
+ tasks.each(&:join)
@@ -0,0 +1,20 @@
1
+ require "thread/task"
2
+
3
+ ident = "foobar"
4
+
5
+ tasks1 = (1...4).map do |i|
6
+ sleep 0.1
7
+ Task.once( i, guard:3, ident: ident ) do |j|
8
+ p j
9
+ end
10
+ end
11
+ tasks2 = (4...8).map do |i|
12
+ sleep 0.1
13
+ Task.once( i, guard:3, ident: ident ) do |j|
14
+ p j
15
+ end
16
+ end
17
+
18
+ tasks1.each(&:join)
19
+ tasks2.each(&:join)
20
+
@@ -0,0 +1,22 @@
1
+
2
+ require "thread/task"
3
+
4
+ begin
5
+ task = Task.new do
6
+ sleep 1
7
+ raise "die now"
8
+ end
9
+
10
+ p :wait
11
+ sleep 2
12
+
13
+ p :value
14
+ p task.value
15
+
16
+ p :do_not_reach
17
+
18
+ rescue => e
19
+ p [e.message, e.backtrace.shift]
20
+
21
+ end
22
+
@@ -0,0 +1,22 @@
1
+
2
+ require "thread/task"
3
+
4
+ begin
5
+ task = Task.new( count: 1 ) do
6
+ sleep 1
7
+ raise "die now"
8
+ end
9
+
10
+ p :wait
11
+ sleep 2
12
+
13
+ p :join
14
+ p task.join
15
+
16
+ p :done
17
+
18
+ rescue => e
19
+ p [e.message, e.backtrace.shift]
20
+
21
+ end
22
+
@@ -0,0 +1,23 @@
1
+ require_relative 'lib/thread/task/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "thread-task"
5
+ spec.version = Thread::Task::VERSION
6
+ spec.authors = ["yorihara"]
7
+ spec.email = ["orihara.yasumi@gmail.com"]
8
+
9
+ spec.summary = %q{ Wrapper library for Thread class for easily describing parallel processing. }
10
+ spec.description = %q{ Wrapper library of Thread class. Thread::Task, Thrad::Task::Pool }
11
+ spec.homepage = "https://github.com/yorihara/thread-task/"
12
+ spec.license = "MIT"
13
+
14
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
15
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
16
+ end
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "rake"
22
+ spec.add_development_dependency "rspec"
23
+ end
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: thread-task
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.0
5
+ platform: ruby
6
+ authors:
7
+ - yorihara
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-05-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: " Wrapper library of Thread class. Thread::Task, Thrad::Task::Pool "
42
+ email:
43
+ - orihara.yasumi@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - ".rspec"
50
+ - ".rubocop.yml"
51
+ - Gemfile
52
+ - README.adoc
53
+ - README.ja.adoc
54
+ - Rakefile
55
+ - bin/console
56
+ - bin/setup
57
+ - lib/thread/task.rb
58
+ - lib/thread/task/base.rb
59
+ - lib/thread/task/version.rb
60
+ - sample/base_1.rb
61
+ - sample/base_pool_1.rb
62
+ - sample/base_pool_2.rb
63
+ - sample/once_delay_1.rb
64
+ - sample/once_delay_2.rb
65
+ - sample/once_guard_1.rb
66
+ - sample/once_guard_2.rb
67
+ - sample/rescue_1.rb
68
+ - sample/rescue_2.rb
69
+ - thread-task.gemspec
70
+ homepage: https://github.com/yorihara/thread-task/
71
+ licenses:
72
+ - MIT
73
+ metadata: {}
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubygems_version: 3.2.15
90
+ signing_key:
91
+ specification_version: 4
92
+ summary: Wrapper library for Thread class for easily describing parallel processing.
93
+ test_files: []