This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
rfc:fiber [2018/04/13 00:11]
rfc:fiber [2018/06/12 07:40] (current)
krakjoe move back to discussion
Line 2: Line 2:
   * Version: 0.1   * Version: 0.1
   * Date: 2017-09-13   * Date: 2017-09-13
-  * Author: Haitao Lvi@lvht.net+  * Author: Haitao Lv<i@lvht.net>, Dmitry Stogov<dmitry@zend.com>, Martin Schröder<m.schroeder2007@googlemail.com>
   * Status: Under Discussion   * Status: Under Discussion
   * First Published at: http://wiki.php.net/rfc/fiber   * First Published at: http://wiki.php.net/rfc/fiber
Line 16: Line 16:
 ===== Proposal ===== ===== Proposal =====
 ==== Why not make it as a Extension? ==== ==== Why not make it as a Extension? ====
 +Fiber is a major language feature, that allows significant benefits for asynchronous frameworks. Providing it as an optional extension, just doesn't make sense.
 ==== Implementation ==== ==== Implementation ====
 +=== Proposed API ===
 <code php> <code php>
 final class Fiber { final class Fiber {
Line 38: Line 41:
   /**   /**
-   start or resume a fiber.+   Start or resume a fiber.
    * If the fiber is not started, call resume will init    * If the fiber is not started, call resume will init
Line 49: Line 52:
   /**   /**
-   throw a exception into the fiber+   Throw an exception into the fiber
 +   *  
 +   * You code can use try/catch to process error in the 
 +   * top level function call. Some framework make heavy 
 +   * usage of this feature.
    */    */
   public function throw(Throwable $e) {}   public function throw(Throwable $e) {}
-  /** @throws \UnexpectedValueException */ 
-  public function __wakeup(): void {} 
-  /** @throws \Error */ 
-  private function __clone() {} 
 } }
 </code> </code>
 +=== Usage Demo ===
 <code php> <code php>
 function sub1() function sub1()
Line 77: Line 79:
 echo $fiber->resume("hello "); // echo "hello world" echo $fiber->resume("hello "); // echo "hello world"
 </code> </code>
 +=== Implementation Detail ===
 +In our simple implementation, we only backup/restore the **zend stack**. We **cannot** pause a Fiber during internal function call like `array_map`.
 ===== Backward Incompatible Changes ===== ===== Backward Incompatible Changes =====
Line 102: Line 107:
 ===== Open Issues ===== ===== Open Issues =====
-<blockquote>What happens if there are internal calls on the call stack?Say something like array_map(function() { await; }, [1, 2, 3]); inside a fiber. Internal calls (using the C stack rather than the VM stack) are usually the problem with this kind of endeavor. +<blockquote>Why not support backup/restore the stack?</blockquote> 
-</blockquote> +Martin Schröder is working on this at https://github.com/fiberphp/fiber-ext/pull/30
- +
-Fiber does not support yielding during the internal call. Calling Fiber::yield in a internal call will trigger a fatal error. +
- +
-<blockquote>How do you determine when a fiber has returned? Looking at the source, it appears Fiber::status() must be used, comparing against constants. Separate methods similar to Generator would be better.</blockquote> +
- +
-Offering methods like <code>Fiber::alive()</code>, <code>Fiber::running()</code> makes any meaningful difference to check the <code>Fiber::status()</code> return value. This is just a coding style issue. And as a language feature, Fiber only offer the essential API and let other works to the userland code. +
- +
-<blockquote>What about throwing exceptions into a fiber?</blockquote> +
- +
-The Fiber::throw(Exception $exception) has been implemented. +
- +
-<blockquote>Using Fiber::resume() to initialize the fiber and resume feels awkward. Separate methods again would be better here, perhaps Fiber::init(...$args) and Fiber::resume($send).</blockquote>+
-Both Ruby's Fiber and Lua's coroutine using the **resume()** API to **init** and **resume** their coroutine. There is no need to offer a **dedicate init** API.+And here is the comparison. 
 +^Property^Stackless Fiber^Native Fiber^ 
 +|1 Minimum Memory Usage|VM stack only (4 KB)|VM & C stack (4 KB + 4 KB)| 
 +|2 Supported Architecturs|any platform|x86 at this time| 
 +|3 Yield in Internal Function|unsupported|supported| 
 +|4 Yield in Iterator|unsupported|supported|
-<blockquote>What happens if the sub1() function in the RFC is invoked outside of a fiber?</blockquote>+Stackless fiber use less memory and are not platform-dependend (1 & 2which makes them very portable and efficient. They do however lack support for anything that involves internal function calls (3) including opcode handlers (4, e.g. foreach loop).
-You will get Fatal Error like+Native fibers are very platform-dependend (2) and use more memory because they do need to allocate a C call stack (1). While memory allocation will be done using mmap() it will still reserve virtual memory (can be problematic for large number of fibers on 32 bit systems due to limited virtual memory addressing). The big advantage is that all kinds of internal function call (3 & 4) are supported without any changes to the existing codebase.
-Fatal errorUncaught ErrorCannot call Fiber::yield out of Fiber+<blockquote>Why not introduce helper like **Fiber::alive(),Fiber::running()**?</blockquote>
-<blockquote>I think keyword here would be beneficialeven if it has a minor BC impactFibers could then be written like generators. `await` or `emit` as a keyword perhaps? This would be a less verbose API, feel less magical (a static method call that actually pauses execution feels out of place), and would allow Fibers to be returned from methods, named functions, etc with less boilerplate.</blockquote>+And as language featureFiber should only offer the essential APIUser can implement these methods in user land code easily.
-Introducing new keywords like await/emit does not offer any essential benefit but only cause BC impact.+<blockquote>Why not introduce a dedicate method other than **Fiber::resume()** for Fiber initialization?</blockquote>
-Both Ruby's Fiber and Lua's coroutine use method to pause and resume their coroutine. There is no need to introduce new keyword.+Both Ruby's Fiber and Lua's coroutine using the same **resume()** API to **init** and **resume** their coroutine.
 ===== Unaffected PHP Functionality ===== ===== Unaffected PHP Functionality =====
Line 135: Line 133:
 ===== Future Scope ===== ===== Future Scope =====
-This sections details areas where the feature might be improved in future, but that are not currently proposed in this RFC. 
-===== Proposed Voting Choices ===== +Syntax like async/await can be implemented in the future, but it's out of the scope of this RFC.
-Simple 50%+1 majority vote.+
 ===== Patches and Tests ===== ===== Patches and Tests =====
Line 160: Line 156:
 ===== Rejected Features ===== ===== Rejected Features =====
-  * await/async keyword 
-  * dedicated Fiber::init API 
rfc/fiber.1523578288.txt.gz · Last modified: 2018/04/13 00:11 by lvht