diff --git a/src/channel.cr b/src/channel.cr index 1411e0c76866..ba20a7d18a85 100644 --- a/src/channel.cr +++ b/src/channel.cr @@ -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 @@ -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