How can I call a block within the execute method of a ScheduledTask?

45 Views Asked by At

I'm trying to call a block within the Concurrent::ScheduledTask#execute method, but the block itself never is executed.

I also tried using Concurrent::ScheduledTask#new method, but the results are the same. I feel there may be a fundamental issue here that I'm missing. Any help would be much appreciated!

require 'concurrent'
##
# A basic Event
class Event
  attr_accessor :ticks
  # @param ticks [Numeric] The amount of ticks we wait before executing this event
  def initialize(ticks = 1.0)
    @ticks = ticks
    puts "Event created with #{@ticks} ticks"
  end
  # Calls the block of this event for execution.
  def execute(&block)
    if !block_given?
      raise AbstractEventExecution.new(self)
    else
      Concurrent::ScheduledTask.execute(@ticks *= 0.75) { block.call }
      puts "Executed in #{@ticks} ticks"
    end
  end
end

class AbstractEventExecution < StandardError
  attr_accessor :event
  def initialize(event)
    @event = event
    super("The Event #{event} was not provided an execution block and is abstract.")
  end
end

event1 = Event.new(105)
event2 = Event.new(1000)
event3 = Event.new(50)
event1.execute { puts "hai from event 1" }
event2.execute { puts "hai from event 2" }
event3.execute { puts "hai from event 3" }

the output is as follows:

Event created with 105 ticks
Event created with 1000 ticks
Event created with 50 ticks
executing an event...
Executed in 78.75 ticks
executing an event...
Executed in 750.0 ticks
executing an event...
Executed in 37.5 ticks

I'm not sure why puts "hai from event x" is never shown at all. Additionally, there is no delay when this executes. There should be a 78.75, 750.0, and 37.5 second delay respectively and there's none at all!

1

There are 1 best solutions below

0
scorix On BEST ANSWER

Both Concurrent::ScheduledTask#new and Concurrent::ScheduledTask#execute returns a [ScheduledTask] object, then the main thread exits.

That's why "hai from event x" is never shown.

require 'concurrent'
##
# A basic Event
class Event
  attr_accessor :ticks
  # @param ticks [Numeric] The amount of ticks we wait before executing this event
  def initialize(ticks = 1.0)
    @ticks = ticks
    puts "Event created with #{@ticks} ticks"
  end

  # Calls the block of this event for execution.
  def execute(&block)
    if !block_given?
      raise AbstractEventExecution.new(self)
    else
      task = Concurrent::ScheduledTask.execute(@ticks *= 0.75) { block.call }
      puts "Executed in #{@ticks} ticks"
      task
    end
  end
end

class AbstractEventExecution < StandardError
  attr_accessor :event

  def initialize(event)
    @event = event
    super("The Event #{event} was not provided an execution block and is abstract.")
  end
end

event1 = Event.new(1)
event2 = Event.new(2)
event3 = Event.new(3)
t1 = event1.execute { puts "hai from event 1" }
t2 = event2.execute { puts "hai from event 2" }
t3 = event3.execute { puts "hai from event 3" }

# waiting for all threads to finish
[t1, t2, t3].map(&:wait)