Skip to content

Instantly share code, notes, and snippets.

@nicoolas25

nicoolas25/equiset.rb

Last active Aug 29, 2015
Embed
What would you like to do?
A small class that allows to loop over a changing set of values
require 'set'
require 'thread'
# A thread safe pool of values that can change.
class EquiSet
def initialize
@sorted_set = SortedSet.new
@mutex = Monitor.new
end
def include?(value)
item = Item.new(value)
@sorted_set.include?(item)
end
def append(value)
safely do
item = Item.new(value)
@sorted_set.add(item)
end
end
# Deletes a value in the pool. Returns nil if the
# value wasn't there and returns the value otherwise.
def delete(value)
safely do
item = Item.new(value)
item = @sorted_set.delete(item)
item && item.value
end
end
# Takes the first non-taken item if the pool.
def take
safely do
# If there is a free item, it is at the begining of
# the set because the way the set is sorted
# see `Item#<=>`.
item = @sorted_set.first
if item && item.free?
# Deletes the matching item
@sorted_set.delete(item)
# Adds a new but non-free item with the same value
new_item = Item.new(item.value, free: false)
@sorted_set.add(new_item)
# Return the value of the matching item
item.value
end
end
end
# Release a non-free value if it exists. It append the value
# at the end of the pool. It returns nil if the value wasn't
# there anymore and the value itself otherwise.
def release(value)
safely do
if delete(value)
append(value)
value
end
end
end
def safely(&block)
@mutex.synchronize do
block.call
end
end
# Define a class that is used by the EquiSet to sort the elements.
# Each item is tagged with its creation date. The Item provide
# the adequate methods to be used in a SortedSet: <=>, hash and eql?.
class Item
attr_reader :value
attr_reader :key
def initialize(value, free: true)
@value = value
@key = Time.now
@free = !!free
end
def free?
@free
end
def <=>(other)
# Same values are the same item
if other.value == @value
return 0
end
# Free items goes first
if other.free? != @free
return @free ? -1 : 1
end
# Order by key (timestamp) otherwise
@key <=> other.key
end
def hash
@value.hash
end
def ==(other)
other.value == @value
end
alias eql? ==
end
end
require_relative 'equiset'
WORKER_COUNT = 5
JOB_COUNT = 10 * WORKER_COUNT
DURATION = 60
# Create and fill the pool with integer jobs
pool = EquiSet.new
(0..JOB_COUNT).each do |i|
pool.append(i)
end
def do_work(pool, thread_id, random)
job = pool.take
if job
puts "<##{thread_id}> taking job ##{job}"
sleep_time = 0.5 + random.rand(1.5)
sleep sleep_time
else
puts "<##{thread_id}> no free job, waiting a few seconds..."
sleep 3
end
ensure
if job
puts "<##{thread_id}> releasing job ##{job}"
pool.release(job)
end
end
# Spawn workers
workers = (0...WORKER_COUNT).map do |i|
Thread.new do
random = Random.new
loop do
do_work(pool, i, random)
end
end
end
# Let the program run during DURATION seconds
sleep DURATION
workers.each_with_index do |worker, i|
puts "Killing worker ##{i}"
worker.kill
end
<#3> taking job #0
<#1> taking job #1
<#2> taking job #2
<#0> taking job #3
<#4> taking job #4
<#2> releasing job #2
<#2> taking job #5
<#1> releasing job #1
<#1> taking job #6
<#4> releasing job #4
<#4> taking job #7
<#3> releasing job #0
<#3> taking job #8
<#0> releasing job #3
<#0> taking job #9
<#2> releasing job #5
<#2> taking job #10
<#3> releasing job #8
<#3> taking job #11
<#1> releasing job #6
<#1> taking job #12
<#2> releasing job #10
<#2> taking job #13
<#4> releasing job #7
<#4> taking job #14
<#0> releasing job #9
<#0> taking job #15
<#0> releasing job #15
<#0> taking job #16
<#1> releasing job #12
<#1> taking job #17
<#2> releasing job #13
<#2> taking job #18
<#4> releasing job #14
<#4> taking job #19
<#3> releasing job #11
<#3> taking job #20
<#2> releasing job #18
<#2> taking job #21
<#1> releasing job #17
<#1> taking job #22
<#0> releasing job #16
<#0> taking job #23
<#2> releasing job #21
<#2> taking job #24
<#0> releasing job #23
<#0> taking job #25
<#1> releasing job #22
<#1> taking job #26
<#4> releasing job #19
<#4> taking job #27
<#3> releasing job #20
<#3> taking job #28
<#1> releasing job #26
<#1> taking job #29
<#2> releasing job #24
<#2> taking job #30
<#4> releasing job #27
<#4> taking job #31
<#3> releasing job #28
<#3> taking job #32
<#2> releasing job #30
<#2> taking job #33
<#4> releasing job #31
<#4> taking job #34
<#0> releasing job #25
<#0> taking job #35
<#1> releasing job #29
<#1> taking job #36
<#2> releasing job #33
<#2> taking job #37
<#3> releasing job #32
<#3> taking job #38
<#1> releasing job #36
<#1> taking job #39
<#4> releasing job #34
<#4> taking job #40
<#0> releasing job #35
<#0> taking job #41
<#3> releasing job #38
<#3> taking job #42
<#2> releasing job #37
<#2> taking job #43
<#4> releasing job #40
<#4> taking job #44
<#1> releasing job #39
<#1> taking job #45
<#2> releasing job #43
<#2> taking job #46
<#0> releasing job #41
<#0> taking job #47
<#3> releasing job #42
<#3> taking job #48
<#4> releasing job #44
<#4> taking job #49
<#1> releasing job #45
<#1> taking job #50
<#2> releasing job #46
<#2> taking job #2
<#0> releasing job #47
<#0> taking job #1
<#1> releasing job #50
<#1> taking job #4
<#3> releasing job #48
<#3> taking job #0
<#4> releasing job #49
<#4> taking job #3
<#0> releasing job #1
<#0> taking job #5
<#2> releasing job #2
<#2> taking job #8
<#4> releasing job #3
<#4> taking job #6
<#0> releasing job #5
<#0> taking job #10
<#1> releasing job #4
<#1> taking job #7
<#3> releasing job #0
<#3> taking job #9
<#2> releasing job #8
<#2> taking job #15
<#4> releasing job #6
<#4> taking job #12
<#0> releasing job #10
<#0> taking job #13
<#1> releasing job #7
<#1> taking job #14
<#4> releasing job #12
<#4> taking job #11
<#2> releasing job #15
<#2> taking job #18
<#3> releasing job #9
<#3> taking job #17
<#2> releasing job #18
<#2> taking job #16
<#1> releasing job #14
<#1> taking job #21
<#0> releasing job #13
<#0> taking job #23
<#4> releasing job #11
<#4> taking job #22
<#3> releasing job #17
<#3> taking job #19
<#2> releasing job #16
<#2> taking job #20
<#4> releasing job #22
<#4> taking job #26
<#0> releasing job #23
<#0> taking job #24
<#1> releasing job #21
<#1> taking job #27
<#3> releasing job #19
<#3> taking job #28
<#0> releasing job #24
<#0> taking job #30
<#4> releasing job #26
<#4> taking job #31
<#2> releasing job #20
<#2> taking job #25
<#1> releasing job #27
<#1> taking job #29
<#3> releasing job #28
<#3> taking job #33
<#0> releasing job #30
<#0> taking job #32
<#1> releasing job #29
<#1> taking job #36
<#4> releasing job #31
<#4> taking job #34
<#0> releasing job #32
<#0> taking job #35
<#2> releasing job #25
<#2> taking job #38
<#1> releasing job #36
<#1> taking job #37
<#3> releasing job #33
<#3> taking job #40
<#4> releasing job #34
<#4> taking job #39
<#2> releasing job #38
<#2> taking job #43
<#1> releasing job #37
<#1> taking job #41
<#0> releasing job #35
<#0> taking job #42
<#1> releasing job #41
<#1> taking job #44
<#2> releasing job #43
<#2> taking job #45
<#0> releasing job #42
<#0> taking job #46
<#3> releasing job #40
<#3> taking job #47
<#4> releasing job #39
<#4> taking job #50
<#3> releasing job #47
<#3> taking job #48
<#1> releasing job #44
<#1> taking job #49
<#2> releasing job #45
<#2> taking job #1
<#0> releasing job #46
<#4> releasing job #50
<#0> taking job #2
<#4> taking job #3
<#2> releasing job #1
<#2> taking job #5
<#3> releasing job #48
<#3> taking job #4
<#1> releasing job #49
<#1> taking job #0
<#4> releasing job #3
<#4> taking job #8
<#2> releasing job #5
<#2> taking job #6
<#0> releasing job #2
<#0> taking job #10
<#3> releasing job #4
<#3> taking job #7
<#0> releasing job #10
<#0> taking job #12
<#1> releasing job #0
<#1> taking job #15
<#4> releasing job #8
<#4> taking job #9
<#3> releasing job #7
<#3> taking job #18
<#2> releasing job #6
<#2> taking job #14
<#1> releasing job #15
<#1> taking job #13
<#4> releasing job #9
<#4> taking job #11
<#0> releasing job #12
<#0> taking job #17
<#3> releasing job #18
<#3> taking job #16
<#1> releasing job #13
<#1> taking job #22
<#4> releasing job #11
<#4> taking job #23
<#2> releasing job #14
<#2> taking job #21
<#0> releasing job #17
<#0> taking job #19
<#1> releasing job #22
<#1> taking job #24
<#3> releasing job #16
<#3> taking job #26
<#4> releasing job #23
<#4> taking job #20
<#2> releasing job #21
<#2> taking job #27
<#1> releasing job #24
<#1> taking job #28
<#0> releasing job #19
<#0> taking job #30
<#0> releasing job #30
<#0> taking job #29
<#1> releasing job #28
<#1> taking job #31
<#3> releasing job #26
<#3> taking job #32
<#4> releasing job #20
<#4> taking job #25
<#2> releasing job #27
<#2> taking job #36
<#0> releasing job #29
<#0> taking job #33
<#2> releasing job #36
<#2> taking job #34
<#1> releasing job #31
<#1> taking job #38
<#0> releasing job #33
<#0> taking job #37
<#4> releasing job #25
<#4> taking job #35
<#3> releasing job #32
<#3> taking job #41
<#2> releasing job #34
<#2> taking job #43
<#1> releasing job #38
<#1> taking job #42
<#0> releasing job #37
<#0> taking job #40
<#1> releasing job #42
<#1> taking job #39
<#4> releasing job #35
<#4> taking job #47
<#2> releasing job #43
<#2> taking job #44
<#3> releasing job #41
<#3> taking job #45
<#0> releasing job #40
<#0> taking job #46
<#1> releasing job #39
<#1> taking job #50
<#2> releasing job #44
<#2> taking job #1
<#0> releasing job #46
<#0> taking job #48
<#3> releasing job #45
<#3> taking job #49
<#1> releasing job #50
<#1> taking job #3
<#4> releasing job #47
<#4> taking job #5
<#2> releasing job #1
<#2> taking job #2
<#0> releasing job #48
<#0> taking job #4
<#1> releasing job #3
<#1> taking job #10
<#3> releasing job #49
<#3> taking job #0
<#0> releasing job #4
<#0> taking job #8
<#4> releasing job #5
<#4> taking job #7
<#2> releasing job #2
<#2> taking job #6
<#0> releasing job #8
<#0> taking job #15
<#3> releasing job #0
<#3> taking job #9
<#1> releasing job #10
<#1> taking job #12
<#0> releasing job #15
<#0> taking job #18
<#2> releasing job #6
<#2> taking job #13
<#3> releasing job #9
<#3> taking job #11
<#4> releasing job #7
<#4> taking job #14
<#1> releasing job #12
<#1> taking job #17
<#3> releasing job #11
<#3> taking job #22
<#2> releasing job #13
<#2> taking job #16
<#3> releasing job #22
<#3> taking job #23
<#0> releasing job #18
<#0> taking job #21
<#1> releasing job #17
<#1> taking job #24
<#4> releasing job #14
<#4> taking job #19
<#2> releasing job #16
<#2> taking job #30
<#1> releasing job #24
<#1> taking job #28
<#3> releasing job #23
<#3> taking job #26
<#2> releasing job #30
<#2> taking job #20
<#0> releasing job #21
<#0> taking job #27
<#4> releasing job #19
<#4> taking job #29
<#0> releasing job #27
<#0> taking job #36
<#2> releasing job #20
<#2> taking job #31
<#1> releasing job #28
<#1> taking job #33
<#3> releasing job #26
<#3> taking job #25
<#0> releasing job #36
<#0> taking job #32
<#4> releasing job #29
<#4> taking job #34
<#1> releasing job #33
<#1> taking job #38
<#2> releasing job #31
<#2> taking job #37
<#3> releasing job #25
<#3> taking job #42
<#3> releasing job #42
<#3> taking job #35
<#0> releasing job #32
<#0> taking job #43
<#4> releasing job #34
<#4> taking job #41
<#2> releasing job #37
<#2> taking job #40
<#0> releasing job #43
<#0> taking job #39
<#1> releasing job #38
<#1> taking job #44
<#2> releasing job #40
<#2> taking job #46
<#0> releasing job #39
<#0> taking job #45
<#3> releasing job #35
<#3> taking job #50
<#1> releasing job #44
<#1> taking job #47
<#4> releasing job #41
<#4> taking job #1
<#2> releasing job #46
<#2> taking job #48
<#4> releasing job #1
<#4> taking job #3
<#1> releasing job #47
<#1> taking job #49
<#2> releasing job #48
<#2> taking job #4
<#0> releasing job #45
<#0> taking job #5
<#3> releasing job #50
<#3> taking job #2
<#4> releasing job #3
<#4> taking job #8
<#0> releasing job #5
<#0> taking job #0
<#2> releasing job #4
<#2> taking job #10
<#1> releasing job #49
<#1> taking job #15
<#2> releasing job #10
<#2> taking job #6
<#3> releasing job #2
<#3> taking job #9
<#4> releasing job #8
<#4> taking job #7
<#0> releasing job #0
<#0> taking job #12
<#1> releasing job #15
<#1> taking job #11
<#1> releasing job #11
<#1> taking job #13
<#3> releasing job #9
<#3> taking job #22
<#0> releasing job #12
<#0> taking job #18
<#4> releasing job #7
<#4> taking job #17
<#2> releasing job #6
<#2> taking job #14
<#1> releasing job #13
<#1> taking job #16
<#3> releasing job #22
<#3> taking job #24
<#2> releasing job #14
<#2> taking job #23
<#0> releasing job #18
<#0> taking job #30
<#4> releasing job #17
<#4> taking job #21
<#1> releasing job #16
<#1> taking job #19
<#2> releasing job #23
<#2> taking job #27
<#0> releasing job #30
<#0> taking job #20
<#3> releasing job #24
<#3> taking job #28
<#3> releasing job #28
<#3> taking job #26
<#4> releasing job #21
<#4> taking job #36
<#2> releasing job #27
<#2> taking job #29
<#1> releasing job #19
<#1> taking job #33
<#0> releasing job #20
<#0> taking job #31
Killing worker #0
Killing worker #1
Killing worker #2
Killing worker #3
Killing worker #4
<#0> releasing job #31
<#1> releasing job #33
<#2> releasing job #29
<#3> releasing job #26
<#4> releasing job #36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment