-
Notifications
You must be signed in to change notification settings - Fork 0
/
ractor.rb
99 lines (81 loc) · 2.53 KB
/
ractor.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
require 'miner_mover/run'
require 'thread'
include MinerMover
run = Run.new.cfg_banner!(duration: 1).start!
run.timestamp!
run.log "Starting #{__FILE__}"
stop_mining = false
Signal.trap("INT") {
run.timestamp!
run.log " *** SIGINT *** Stop Mining"
stop_mining = true
}
# the moving operation executes in its own Ractor
mover = Ractor.new(run) { |r|
r.log "MOVE Moving operation started"
# use queue to distribute incoming ore to mover threads
queue = Thread::Queue.new
# store the mover threads in an array
movers = Array.new(r.num_movers) { |i|
Thread.new {
m = r.new_mover
m.log "MOVE Mover #{i} started"
# movers pull from the queue, load the ore, and move it
loop {
ore = queue.pop
break if ore == :quit
m.load_ore ore # move_batch happens when a batch is full
}
# move any remaining ore and quit
m.move_batch while m.batch > 0
m.log "QUIT #{m.status}"
m
}
}
# Miners feed this Ractor with ore
# Pass the ore into a queue for the movers
# When the miners say to quit, tell the movers to quit
r.log "WAIT Waiting for ore ..."
loop {
# when the Ractor gets ore, push it into the queue
ore = Ractor.recv
break if ore == :quit
queue.push ore
}
# tell all the movers to quit and gather their results
r.num_movers.times { queue.push :quit }
movers.map { |thr| thr.value.ore_moved }.sum
}
# our mining operation executes in the main Ractor, here
run.log "MINE Mining operation started [ctrl-c] to stop"
# store the miner threads in an array
miners = Array.new(run.num_miners) { |i|
Thread.new {
m = run.new_miner
m.log "MINE Miner #{i} started"
ore_mined = 0
while !stop_mining # SIGINT will trigger stop_mining = true
ore = m.mine_ore
ore_mined += ore
mover.send ore if ore > 0 # send any ore mined to the mover Ractor
# stop mining after a while
if run.time_limit? or run.ore_limit?(ore_mined)
run.timestamp!
m.log format("Mining limit reached: %s", Ore.display(ore_mined))
stop_mining = true
end
end
m.log format("MINE Miner %i finished after mining %s",
i, Ore.display(ore_mined))
ore_mined
}
}
# wait on all mining threads to stop
ore_mined = miners.map { |thr| thr.value }.sum
run.log format("MINE %s mined (%i)", Ore.display(ore_mined), ore_mined)
# tell mover to quit
mover.send :quit
# wait for results
ore_moved = mover.take
run.log format("MOVE %s moved (%i)", Ore.display(ore_moved), ore_moved)
run.timestamp!