1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Update fiber scheduler documentation.

This commit is contained in:
Samuel Williams 2020-12-22 10:55:29 +13:00
parent edb76e8765
commit 93a56a5e98
Notes: git 2020-12-22 19:51:27 +09:00
2 changed files with 73 additions and 17 deletions

View file

@ -354,11 +354,12 @@ Outstanding ones only.
* Symbol#name has been added, which returns the name of the symbol * Symbol#name has been added, which returns the name of the symbol
if it is named. The returned string is frozen. [[Feature #16150]] if it is named. The returned string is frozen. [[Feature #16150]]
* Thread * Fiber
* Introduce Fiber.set_scheduler for intercepting blocking operations and * Introduce Fiber.set_scheduler for intercepting blocking operations and
Fiber.scheduler for accessing the current scheduler. See Fiber.scheduler for accessing the current scheduler. See
rdoc-ref:scheduler.md for more details. [[Feature #16786]] rdoc-ref:fiber.md for more details about what operations are supported and
how to implement the scheduler hooks. [[Feature #16786]]
* Fiber.blocking? tells whether the current execution context is * Fiber.blocking? tells whether the current execution context is
blocking. [[Feature #16786]] blocking. [[Feature #16786]]
@ -366,6 +367,8 @@ Outstanding ones only.
* Thread#join invokes the scheduler hooks `block`/`unblock` in a * Thread#join invokes the scheduler hooks `block`/`unblock` in a
non-blocking execution context. [[Feature #16786]] non-blocking execution context. [[Feature #16786]]
* Thread
* Thread.ignore_deadlock accessor has been added for disabling the * Thread.ignore_deadlock accessor has been added for disabling the
default deadlock detection, allowing the use of signal handlers to default deadlock detection, allowing the use of signal handlers to
break deadlock. [[Bug #13768]] break deadlock. [[Bug #13768]]

View file

@ -1,4 +1,34 @@
# Scheduler # Fiber
Fibers provide a mechanism for cooperative concurrency.
## Context Switching
Fibers execute a user-provided block. During the execution, the block may call `Fiber.yield` or `Fiber.transfer` to switch to another fiber. `Fiber#resume` is used to continue execution from the point where `Fiber.yield` was called.
``` ruby
#!/usr/bin/env ruby
puts "1: Start program."
f = Fiber.new do
puts "3: Entered fiber."
Fiber.yield
puts "5: Resumed fiber."
end
puts "2: Resume fiber first time."
f.resume
puts "4: Resume fiber second time."
f.resume
puts "6: Finished."
```
This program demonstrates the flow control of fibers.
## Scheduler
The scheduler interface is used to intercept blocking operations. A typical The scheduler interface is used to intercept blocking operations. A typical
implementation would be a wrapper for a gem like `EventMachine` or `Async`. This implementation would be a wrapper for a gem like `EventMachine` or `Async`. This
@ -6,11 +36,23 @@ design provides separation of concerns between the event loop implementation
and application code. It also allows for layered schedulers which can perform and application code. It also allows for layered schedulers which can perform
instrumentation. instrumentation.
## Interface To set the scheduler for the current thread:
``` ruby
Fiber.set_schduler(MyScheduler.new)
```
When the thread exits, there is an implicit call to `set_scheduler`:
``` ruby
Fiber.set_scheduler(nil)
```
### Interface
This is the interface you need to implement. This is the interface you need to implement.
~~~ ruby ``` ruby
class Scheduler class Scheduler
# Wait for the specified process ID to exit. # Wait for the specified process ID to exit.
# This hook is optional. # This hook is optional.
@ -67,23 +109,23 @@ class Scheduler
# Implement event loop here. # Implement event loop here.
end end
end end
~~~ ```
Additional hooks may be introduced in the future, we will use feature detection Additional hooks may be introduced in the future, we will use feature detection
in order to enable these hooks. in order to enable these hooks.
## Non-blocking Execution ### Non-blocking Execution
The scheduler hooks will only be used in special non-blocking execution The scheduler hooks will only be used in special non-blocking execution
contexts. Non-blocking execution contexts introduce non-determinism because the contexts. Non-blocking execution contexts introduce non-determinism because the
execution of scheduler hooks may introduce context switching points into your execution of scheduler hooks may introduce context switching points into your
program. program.
### Fibers #### Fibers
Fibers can be used to create non-blocking execution contexts. Fibers can be used to create non-blocking execution contexts.
~~~ ruby ``` ruby
Fiber.new do Fiber.new do
puts Fiber.current.blocking? # false puts Fiber.current.blocking? # false
@ -96,43 +138,54 @@ Fiber.new do
# Will invoke `Fiber.scheduler&.kernel_sleep`. # Will invoke `Fiber.scheduler&.kernel_sleep`.
sleep(n) sleep(n)
end.resume end.resume
~~~ ```
We also introduce a new method which simplifies the creation of these We also introduce a new method which simplifies the creation of these
non-blocking fibers: non-blocking fibers:
~~~ ruby ``` ruby
Fiber.schedule do Fiber.schedule do
puts Fiber.current.blocking? # false puts Fiber.current.blocking? # false
end end
~~~ ```
The purpose of this method is to allow the scheduler to internally decide the The purpose of this method is to allow the scheduler to internally decide the
policy for when to start the fiber, and whether to use symmetric or asymmetric policy for when to start the fiber, and whether to use symmetric or asymmetric
fibers. fibers.
### IO You can also create blocking execution contexts:
``` ruby
Fiber.new(blocking: true) do
# Won't use the scheduler:
sleep(n)
end
```
However you should generally avoid this unless you are implementing a scheduler.
#### IO
By default, I/O is non-blocking. Not all operating systems support non-blocking By default, I/O is non-blocking. Not all operating systems support non-blocking
I/O. Windows is a notable example where socket I/O can be non-blocking but pipe I/O. Windows is a notable example where socket I/O can be non-blocking but pipe
I/O is blocking. Provided that there *is* a scheduler and the current thread *is I/O is blocking. Provided that there *is* a scheduler and the current thread *is
non-blocking*, the operation will invoke the scheduler. non-blocking*, the operation will invoke the scheduler.
### Mutex #### Mutex
The `Mutex` class can be used in a non-blocking context and is fiber specific. The `Mutex` class can be used in a non-blocking context and is fiber specific.
### ConditionVariable #### ConditionVariable
The `ConditionVariable` class can be used in a non-blocking context and is The `ConditionVariable` class can be used in a non-blocking context and is
fiber-specific. fiber-specific.
### Queue / SizedQueue #### Queue / SizedQueue
The `Queue` and `SizedQueue` classses can be used in a non-blocking context and The `Queue` and `SizedQueue` classses can be used in a non-blocking context and
are fiber-specific. are fiber-specific.
### Thread #### Thread
The `Thread#join` operation can be used in a non-blocking context and is The `Thread#join` operation can be used in a non-blocking context and is
fiber-specific. fiber-specific.