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:
parent
edb76e8765
commit
93a56a5e98
Notes:
git
2020-12-22 19:51:27 +09:00
2 changed files with 73 additions and 17 deletions
7
NEWS.md
7
NEWS.md
|
@ -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]]
|
||||||
|
|
|
@ -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.
|
Loading…
Reference in a new issue