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
|
# Event Loop
This guide gives an overview of how the event loop is implemented.
## Overview
{ruby Async::Reactor} provides the event loop and sits at the root of any task tree. Work is scheduled by adding {ruby Async::Task} instances to the reactor. When you invoke {ruby Async::Reactor#async}, the parent task is determined by calling {ruby Async::Task.current?} which uses fiber local storage. A slightly more efficient method is to use {ruby Async::Task#async}, which uses `self` as the parent task.
~~~ ruby
require 'async'
def sleepy(duration, task: Async::Task.current)
task.async do |subtask|
subtask.annotate "I'm going to sleep #{duration}s..."
subtask.sleep duration
puts "I'm done sleeping!"
end
end
def nested_sleepy(task: Async::Task.current)
task.async do |subtask|
subtask.annotate "Invoking sleepy 5 times..."
5.times do |index|
sleepy(index, task: subtask)
end
end
end
Async do |task|
task.annotate "Invoking nested_sleepy..."
subtask = nested_sleepy
# Print out all running tasks in a tree:
task.print_hierarchy($stderr)
# Kill the subtask
subtask.stop
end
~~~
### Thread Safety
Most methods of the reactor and related tasks are not thread-safe, so you'd typically have [one reactor per thread or process](https://github.com/socketry/async-container).
### Embedding Reactors
`Async::Reactor#run` will run until the reactor runs out of work to do. To run a single iteration of the reactor, use `Async::Reactor#run_once`
~~~ ruby
require 'async'
Async.logger.debug!
reactor = Async::Reactor.new
# Run the reactor for 1 second:
reactor.async do |task|
task.sleep 1
puts "Finished!"
end
while reactor.run_once
# Round and round we go!
end
~~~
You can use this approach to embed the reactor in another event loop.
### Stopping Reactors
`Async::Reactor#stop` will stop the current reactor and all children tasks.
### Interrupting Reactors
`Async::Reactor#interrupt` can be called safely from a different thread (or signal handler) and will cause the reactor to invoke `#stop`.
|