miner_mover 0.1.1.1 → 0.1.2.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.
- checksums.yaml +4 -4
- data/README.md +130 -44
- data/Rakefile +23 -7
- data/VERSION +1 -1
- data/demo/process_socket.rb +1 -1
- data/lib/miner_mover.rb +8 -6
- data/miner_mover.gemspec +12 -18
- metadata +4 -78
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4901bb324083ef4c73adb1ed174794d0c90821fe9eae11f7a9935690dab821e3
|
4
|
+
data.tar.gz: ad001e368e39ab5e11bc2750d37e6aee4ba6dc42be2e08d0f346f57065c12a88
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 22db270f2c03cbbcace66a2724ed8c98315b14caa3d0d135e02e04d98b9baaaa49c9b2bc3aaa7f64b35fd6d5416611e29d344582dbc3cc5820ce351ea0a6b22c
|
7
|
+
data.tar.gz: 7ef93f90a90e33c34e3a5412495a828fb9030ccb160389b764448bf5e7e9dfe022687b1db9ba6e64e7418af541a681033d437b21ff50ebba320b18fa4a9c6095
|
data/README.md
CHANGED
@@ -42,51 +42,57 @@ configured via `:work_type`
|
|
42
42
|
|
43
43
|
# Usage
|
44
44
|
|
45
|
+
You'll want to use **Ruby 3.1+** (CRuby) to make the most of Ractors, Fibers,
|
46
|
+
and Fiber::Scheduler.
|
47
|
+
|
48
|
+
This gem can be used on JRuby and TruffleRuby, but several concurrency options
|
49
|
+
are not available: process forking, Ractors, and Fiber::Scheduler.
|
50
|
+
However, their threading performance exceeds CRuby's as they don't have a
|
51
|
+
Global VM Lock (GVL).
|
52
|
+
|
45
53
|
## Install
|
46
54
|
|
47
|
-
|
55
|
+
Right now, a gem installation only provides the Miner Mover library.
|
56
|
+
Use the **Development** process below to access all of the demonstration
|
57
|
+
scripts showing the different concurrency strategies.
|
48
58
|
|
49
|
-
|
59
|
+
`gem install miner_mover`
|
50
60
|
|
51
|
-
|
52
|
-
* minitest
|
53
|
-
* dotcfg
|
54
|
-
* fiber_scheduler
|
61
|
+
For Ruby 3.1+ on linux, you'll also want:
|
55
62
|
|
56
|
-
`gem install
|
63
|
+
`gem install fiber_scheduler io-event`
|
57
64
|
|
58
|
-
|
65
|
+
## Development
|
59
66
|
|
60
67
|
```
|
61
68
|
git clone https://github.com/rickhull/miner_mover
|
62
69
|
cd miner_mover
|
70
|
+
bundle config set --local with development
|
71
|
+
bundle install
|
63
72
|
```
|
64
73
|
|
65
|
-
###
|
74
|
+
### Rake Tasks
|
66
75
|
|
67
76
|
Try: `rake -T` to see available [Rake tasks](Rakefile)
|
68
77
|
|
69
78
|
```
|
70
79
|
$ rake -T
|
71
80
|
|
72
|
-
rake
|
73
|
-
rake
|
74
|
-
rake
|
75
|
-
rake
|
76
|
-
rake
|
77
|
-
rake
|
78
|
-
rake
|
79
|
-
rake
|
80
|
-
rake
|
81
|
-
rake serial # run demo/serial
|
81
|
+
rake config # Run demo/config.rb
|
82
|
+
rake demo # Run all demos
|
83
|
+
rake fiber # Run demo/fiber.rb
|
84
|
+
rake fiber_scheduler # Run demo/fiber_scheduler.rb
|
85
|
+
rake jvm_demo # Run JVM compatible demos
|
86
|
+
rake process_pipe # Run demo/process_pipe.rb
|
87
|
+
rake process_socket # Run demo/process_socket.rb
|
88
|
+
rake ractor # Run demo/ractor.rb
|
89
|
+
rake serial # Run demo/serial.rb
|
82
90
|
rake test # Run tests
|
83
|
-
rake thread #
|
91
|
+
rake thread # Run demo/thread.rb
|
84
92
|
```
|
85
93
|
|
86
94
|
Try: `rake test`
|
87
95
|
|
88
|
-
## Rake Tasks
|
89
|
-
|
90
96
|
Included demonstration scripts can be executed via Rake tasks.
|
91
97
|
The following order is recommended:
|
92
98
|
|
@@ -101,7 +107,7 @@ The following order is recommended:
|
|
101
107
|
Try each task; there will be about 6 seconds worth of many lines of output
|
102
108
|
logging. These rake tasks correspond to the scripts within [`demo/`](demo/).
|
103
109
|
|
104
|
-
|
110
|
+
### Satisfy `LOAD_PATH`
|
105
111
|
|
106
112
|
Rake tasks take care of `LOAD_PATH`, so the following is
|
107
113
|
**only necessary when *not* using rake tasks**:
|
@@ -111,41 +117,81 @@ Rake tasks take care of `LOAD_PATH`, so the following is
|
|
111
117
|
`require 'miner_mover'` will work.
|
112
118
|
* This project does not use `require_relative`
|
113
119
|
|
114
|
-
|
120
|
+
### Exploration in `irb`
|
115
121
|
|
116
122
|
`$ irb -I lib`
|
117
123
|
|
118
124
|
```
|
119
|
-
irb(main):001:0>
|
125
|
+
irb(main):001:0> require 'miner_mover/worker'
|
126
|
+
=> true
|
127
|
+
|
128
|
+
irb(main):002:0> include MinerMover
|
120
129
|
=> Object
|
121
130
|
|
122
|
-
irb(main):
|
131
|
+
irb(main):003:0> miner = Miner.new
|
123
132
|
=>
|
124
|
-
#<MinerMover::Miner:
|
133
|
+
#<MinerMover::Miner:0x00007fbee8a3a080
|
125
134
|
...
|
126
135
|
|
127
|
-
irb(main):
|
128
|
-
=> 0
|
129
|
-
|
130
|
-
irb(main):004:0> miner.mine_ore 5
|
131
|
-
=> 3
|
132
|
-
|
133
|
-
irb(main):005:0> miner.mine_ore 20
|
134
|
-
=> 6483
|
135
|
-
|
136
|
-
irb(main):006:0> mover = Mover.new
|
136
|
+
irb(main):004:0> mover = Mover.new
|
137
137
|
=>
|
138
|
-
#<MinerMover::Mover:
|
138
|
+
#<MinerMover::Mover:0x00007fbee8a8a6c0
|
139
139
|
...
|
140
140
|
|
141
|
-
irb(main):
|
142
|
-
=>
|
143
|
-
|
144
|
-
|
145
|
-
=>
|
141
|
+
irb(main):005:0> miner.state
|
142
|
+
=>
|
143
|
+
{:id=>"00050720",
|
144
|
+
:logging=>false,
|
145
|
+
:debugging=>false,
|
146
|
+
:timer=>10200,
|
147
|
+
:variance=>0,
|
148
|
+
:depth=>5,
|
149
|
+
:partial_reward=>false}
|
150
|
+
|
151
|
+
irb(main):006:0> mover.state
|
152
|
+
=>
|
153
|
+
{:id=>"00057860",
|
154
|
+
:logging=>false,
|
155
|
+
:debugging=>false,
|
156
|
+
:timer=>10456,
|
157
|
+
:variance=>0,
|
158
|
+
:work_type=>:cpu,
|
159
|
+
:batch_size=>10000000,
|
160
|
+
:batch=>0,
|
161
|
+
:batches=>0,
|
162
|
+
:ore_moved=>0}
|
163
|
+
|
164
|
+
irb(main):007:0> miner.mine_ore
|
165
|
+
=> 7
|
166
|
+
|
167
|
+
irb(main):008:0> mover.load_ore 7
|
168
|
+
=> 7
|
169
|
+
|
170
|
+
irb(main):009:0> miner.state
|
171
|
+
=>
|
172
|
+
{:id=>"00050720",
|
173
|
+
:logging=>false,
|
174
|
+
:debugging=>false,
|
175
|
+
:timer=>28831,
|
176
|
+
:variance=>0,
|
177
|
+
:depth=>5,
|
178
|
+
:partial_reward=>false}
|
179
|
+
|
180
|
+
irb(main):010:0> mover.state
|
181
|
+
=>
|
182
|
+
{:id=>"00057860",
|
183
|
+
:logging=>false,
|
184
|
+
:debugging=>false,
|
185
|
+
:timer=>27959,
|
186
|
+
:variance=>0,
|
187
|
+
:work_type=>:cpu,
|
188
|
+
:batch_size=>10000000,
|
189
|
+
:batch=>7,
|
190
|
+
:batches=>0,
|
191
|
+
:ore_moved=>0}
|
146
192
|
```
|
147
193
|
|
148
|
-
|
194
|
+
### Included scripts
|
149
195
|
|
150
196
|
These scripts implement a full miner mover simulation using different
|
151
197
|
multitasking paradigms in Ruby.
|
@@ -165,6 +211,46 @@ multiple miners or movers.
|
|
165
211
|
|
166
212
|
Execute via e.g. `ruby -Ilib demo/thread.rb`
|
167
213
|
|
214
|
+
### Concurrency Strategies
|
215
|
+
|
216
|
+
#### [Serial](demo/serial.rb)
|
217
|
+
|
218
|
+
One miner, one mover. The miner mines to a depth, then loads the ore.
|
219
|
+
When the mover has a full batch, the batch is moved while the miner waits.
|
220
|
+
|
221
|
+
#### [Fibers](demo/fiber.rb)
|
222
|
+
|
223
|
+
Without a Fiber Scheduler, this just changes some organizational things.
|
224
|
+
Again, one miner, one mover. The mover has its own fiber, and the mining
|
225
|
+
fiber can pass ore to the moving fiber. There is no concurrency, so the
|
226
|
+
performance is roughly the same as before.
|
227
|
+
|
228
|
+
#### [Fiber Scheduler](demo/fiber_scheduler.rb)
|
229
|
+
|
230
|
+
TBD
|
231
|
+
|
232
|
+
#### [Threads](demo/thread.rb)
|
233
|
+
|
234
|
+
An array of mining threads and an array of moving threads.
|
235
|
+
A single shared queue for loading ore from miners to movers.
|
236
|
+
All threads contend for the same execution lock (GVL).
|
237
|
+
|
238
|
+
#### [Ractors](demo/ractor.rb)
|
239
|
+
|
240
|
+
Moving threads execute in their own ractor.
|
241
|
+
Mining threads contend against mining threads. Moving threads, likewise.
|
242
|
+
|
243
|
+
#### [Processes with pipes](demo/process_pipe.rb)
|
244
|
+
|
245
|
+
Similar to ractors, but using `Process.fork` for movers, using a pipe to send
|
246
|
+
ore from the parent mining process.
|
247
|
+
|
248
|
+
#### [Processes with sockets](demo/process_socket.rb)
|
249
|
+
|
250
|
+
As above, but with Unix sockets (*not* network sockets), using any of
|
251
|
+
`SOCK_STREAM` `SOCK_DGRAM` `SOCK_SEQPACKET` socket types.
|
252
|
+
In all cases, ore amounts are 4 bytes so the types behave roughly equivalently.
|
253
|
+
|
168
254
|
# Multitasking
|
169
255
|
|
170
256
|
*Multitasking* here means "the most general sense of performing several tasks
|
data/Rakefile
CHANGED
@@ -1,27 +1,43 @@
|
|
1
|
-
|
1
|
+
#
|
2
|
+
# test task
|
3
|
+
#
|
2
4
|
|
5
|
+
require 'rake/testtask'
|
3
6
|
Rake::TestTask.new :test do |t|
|
4
7
|
t.pattern = "test/*.rb"
|
5
8
|
t.warning = true
|
6
9
|
end
|
7
|
-
|
8
|
-
desc "rake test"
|
9
10
|
task default: :test
|
10
11
|
|
12
|
+
#
|
13
|
+
# demo tasks
|
14
|
+
#
|
15
|
+
|
16
|
+
if ENV['RUBYOPT'].nil? or ENV['RUBYOPT'].empty?
|
17
|
+
flags = ['-I', File.join(__dir__, 'lib')]
|
18
|
+
else
|
19
|
+
flags = nil # subprocesses will have RUBYOPT
|
20
|
+
end
|
21
|
+
|
22
|
+
# create a rake task to run each script in demo/
|
11
23
|
Dir['demo/*.rb'].each { |demo_path|
|
12
24
|
name = File.basename(demo_path, '.rb')
|
13
|
-
desc "
|
14
|
-
task(name) {
|
25
|
+
desc "Run #{demo_path}"
|
26
|
+
task(name) { ruby *flags, demo_path }
|
15
27
|
}
|
16
28
|
|
17
29
|
# jruby / truffleruby lack fiber_scheduler, Ractor, and Process#fork
|
18
|
-
desc "
|
30
|
+
desc "Run JVM compatible demos"
|
19
31
|
task jvm_demo: [:serial, :fiber, :thread]
|
20
32
|
|
21
|
-
desc "
|
33
|
+
desc "Run all demos"
|
22
34
|
task demo: [:serial, :fiber, :fiber_scheduler,
|
23
35
|
:thread, :ractor, :process_pipe, :process_socket]
|
24
36
|
|
37
|
+
#
|
38
|
+
# release tasks
|
39
|
+
#
|
40
|
+
|
25
41
|
begin
|
26
42
|
require 'buildar'
|
27
43
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.2.3
|
data/demo/process_socket.rb
CHANGED
data/lib/miner_mover.rb
CHANGED
@@ -3,20 +3,22 @@ module MinerMover
|
|
3
3
|
|
4
4
|
# $/ is the default line separator: "\n"
|
5
5
|
def self.puts(str, io = $stdout, separator = LINE_SEP)
|
6
|
-
self.
|
6
|
+
self.write(io, str + separator)
|
7
7
|
end
|
8
8
|
|
9
|
-
def self.
|
9
|
+
def self.write(io, str)
|
10
|
+
# nonblocking write attempt; ensure the full string is written
|
10
11
|
begin
|
11
|
-
# nonblocking write attempt; ensure the full string is written
|
12
|
-
size = str.bytesize
|
13
12
|
num_bytes = io.write_nonblock(str)
|
14
|
-
# blocking write if nonblocking write comes up short
|
15
|
-
io.write str.byteslice(num_bytes, size - num_bytes) if num_bytes < size
|
16
13
|
rescue IO::WaitWritable, Errno::EINTR
|
17
14
|
IO.select([], [io]) # wait until writable
|
18
15
|
retry
|
19
16
|
end
|
17
|
+
# blocking write if nonblocking write comes up short
|
18
|
+
if num_bytes < str.bytesize
|
19
|
+
io.write str.byteslice(num_bytes, str.bytesize - num_bytes)
|
20
|
+
end
|
21
|
+
nil
|
20
22
|
end
|
21
23
|
|
22
24
|
def self.log_fmt(timer, id, msg)
|
data/miner_mover.gemspec
CHANGED
@@ -5,29 +5,23 @@ Gem::Specification.new do |s|
|
|
5
5
|
s.description = <<EOF
|
6
6
|
Fundamentally, we have a set of miners and a set of movers. A miner takes some amount of time to mine ore, which is given to a mover. When a mover has enough ore for a full batch, the delivery takes some amount of time before more ore can be loaded.
|
7
7
|
EOF
|
8
|
-
|
8
|
+
s.authors = ["Rick Hull"]
|
9
9
|
s.homepage = "https://github.com/rickhull/miner_mover"
|
10
10
|
s.license = "LGPL-3.0"
|
11
11
|
|
12
|
-
s.required_ruby_version = "
|
12
|
+
s.required_ruby_version = "> 2"
|
13
13
|
|
14
14
|
s.version = File.read(File.join(__dir__, 'VERSION')).chomp
|
15
15
|
|
16
|
-
s.files =
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
s.files = Dir[
|
17
|
+
'miner_mover.gemspec',
|
18
|
+
'VERSION',
|
19
|
+
'README.md',
|
20
|
+
'Rakefile',
|
21
|
+
'lib/**/*.rb',
|
22
|
+
'test/**/*.rb',
|
23
|
+
'demo/**/*.rb',
|
24
|
+
]
|
20
25
|
|
21
|
-
s.
|
22
|
-
|
23
|
-
s.requirements << "For all features and best performance:"
|
24
|
-
s.requirements << "gem install rake minitest fiber_scheduler"
|
25
|
-
s.requirements << "For dev tools:"
|
26
|
-
s.requirements << "gem install buildar flog flay"
|
27
|
-
|
28
|
-
s.add_development_dependency "rake", "~> 13.0" # CVE-2020-8130
|
29
|
-
s.add_development_dependency "minitest", "~> 5.0"
|
30
|
-
s.add_development_dependency "buildar", "~> 3.0"
|
31
|
-
s.add_development_dependency "flog", "~> 0"
|
32
|
-
s.add_development_dependency "flay", "~> 0"
|
26
|
+
s.add_runtime_dependency "dotcfg", "~> 1.0"
|
33
27
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: miner_mover
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rick Hull
|
@@ -24,76 +24,6 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: rake
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '13.0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '13.0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: minitest
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '5.0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '5.0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: buildar
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '3.0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '3.0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: flog
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - "~>"
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - "~>"
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: flay
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - "~>"
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - "~>"
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
27
|
description: 'Fundamentally, we have a set of miners and a set of movers. A miner
|
98
28
|
takes some amount of time to mine ore, which is given to a mover. When a mover has
|
99
29
|
enough ore for a full batch, the delivery takes some amount of time before more
|
@@ -133,7 +63,7 @@ require_paths:
|
|
133
63
|
- lib
|
134
64
|
required_ruby_version: !ruby/object:Gem::Requirement
|
135
65
|
requirements:
|
136
|
-
- - "
|
66
|
+
- - ">"
|
137
67
|
- !ruby/object:Gem::Version
|
138
68
|
version: '2'
|
139
69
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
@@ -141,12 +71,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
141
71
|
- - ">="
|
142
72
|
- !ruby/object:Gem::Version
|
143
73
|
version: '0'
|
144
|
-
requirements:
|
145
|
-
|
146
|
-
- gem install rake minitest fiber_scheduler
|
147
|
-
- 'For dev tools:'
|
148
|
-
- gem install buildar flog flay
|
149
|
-
rubygems_version: 3.3.20
|
74
|
+
requirements: []
|
75
|
+
rubygems_version: 3.4.1
|
150
76
|
signing_key:
|
151
77
|
specification_version: 4
|
152
78
|
summary: This project provides a basic concurrency problem useful for exploring different
|