Skip to content

Commit

Permalink
fixup: select can check if any op is ready before spawning fibers
Browse files Browse the repository at this point in the history
  • Loading branch information
ysbaddaden committed Feb 10, 2019
1 parent f4b0854 commit edbf15f
Showing 1 changed file with 12 additions and 9 deletions.
21 changes: 12 additions & 9 deletions src/channel.cr
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,20 @@ abstract class Channel(T)
# execution so the *fibers* array will always be filled with all fibers, so
# any ready operation can cancel all other fibers ASAP.
def self.select(ops : Tuple | Array, has_else = false)
# fast path: check if any clause is ready
ops.each_with_index do |op, i|
if op.ready?
return {i, op.execute}
end
end

if has_else
return {ops.size, nil}
end

# slow path: spawn fibers to wait on each clause
main = Fiber.current
fibers = Array(Fiber).new(ops.size)

waiting = 0
index = -1
value = nil

Expand All @@ -128,13 +138,6 @@ abstract class Channel(T)
break
end

if has_else && (waiting += 1) == ops.size
cancel_select_actions(ops, fibers, i)
index = ops.size
Crystal::Scheduler.enqueue(main)
break
end

op.wait
Crystal::Scheduler.reschedule
end
Expand Down

0 comments on commit edbf15f

Please sign in to comment.