Hi, all,

I have updated the RFC https://wiki.php.net/rfc/fiber

changes list:

- introduce the `throw(Exception $exceptin)` API
- record issues discussed

> On Feb 9, 2018, at 08:12, Haitao Lv <i...@lvht.net> wrote:
> 
>> 
>> On Feb 9, 2018, at 06:22, Niklas Keller <m...@kelunik.com> wrote:
>> 
>>> 
>>>> - 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 IMO. e.g.:
>>> Fiber::alive(), Fiber::suspended(), Fiber::running()
>>> 
>>> Offering methods like Fiber::alive, Fiber::running makes no difference to
>>> check the Fiber::status() return value. This is just a style issue. And as
>>> a language feature,
>>> Fiber only offer the essential API and let other works to the user land.
>> 
>> 
>> The language should offer a sane API, not the absolute minimum required to
>> work for these things.
> 
> The Ruby's Fiber do offer a live? method but does not have a getStatus method.
> The Lua's coroutine only offer a status method.
> 
> So do we really need to offer three additional helper method? Or what is your
> advice about these API?
> 
>> 
>>>> - What about throwing exceptions into a fiber?
>>> 
>>> Currently does not support throw exception into the fiber. User land code
>>> could check
>>> the value of Fiber::yield and throw exception themselves. The Ruby's Fiber
>>> and Lua's
>>> coroutine also does not support such api as well.
>> 
>> 
>> And throw the exception where? That means async code with fibers can't
>> really handle errors?
> 
> Actually you can transfer any thing to Fiber by the resume method. And you can
> check the return value of Fiber::yield to handle error.
> 
> Fiber is designed as a primitive, low level, and lightweight feature. User 
> land
> code seldom not need to use them directly in your normal code.
> So the following is not a big problem,
> 
> $a = Fiber::yield(...);
> if ($a === false) {
>   throw new Exception(...);
> }
> 
> And both the Ruby and Lua does not offer such API as well.
>> 
>>> 
>>>> 
>>>> - 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).
>>> 
>>> All Fiber created with a suspended status. So make resume to do both the
>>> init and resume
>>> do make sense.
>>> 
>> 
>> It does't make sense to me. Reading the example in the README and
>> understanding why the first resume() takes two arguments instead of one
>> took me quite some minutes.
> 
> This Ruby's Fiber and Lua's coroutine using one resume API to init and resume
> the coroutine. I do not think a dedicate is really required.
> 
> The generator cannot be init by it's send method. And if you want to implement
> coroutine feature(without stack) by it, you have to write code
> 
> function run() {
>    if ($this->beforeFirstYield) {
>        $this->beforeFirstYield = false;
>        return $this->coroutine->current();
>    } else {
>        $retval = $this->coroutine->send($this->sendValue);
>        $this->sendValue = null;
>        return $retval;      
>    }   
> }
> 
> It is verbose.
> 
> See 
> https://nikic.github.io/2012/12/22/Cooperative-multitasking-using-coroutines-in-PHP.html
> 
>> 
>>> Please see Ruby Fiber API https://ruby-doc.org/core-2.2.0/Fiber.html.
>>> 
>>>> 
>>>> - What happens if the sub1() function in the RFC is invoked outside of a
>>> fiber?
>>> 
>>> You will get a Fatal Error like
>>> Fatal error: Uncaught Error: Cannot call Fiber::yield out of Fiber
>>> 
>>>> - I think a keyword here would be beneficial, even if it has a minor BC
>>> impact. Fibers 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.
>>> 
>>> Wishing this to be accepted by the community in the PHP 7.3, so no keyword
>>> is accepted.
>>> And if the community cannot accept, the Fiber can be still distributed as
>>> a standalone
>>> extension. So we cannot depend on a new keyword.
>> 
>> 
>> Right, if it's a standalone extension it can't use a new keyword, but as a
>> language feature it totally can.
> 
> In my opinion, using a keyword or call a method is just a coding style 
> problem.
> Introducing a new keyword does not offer any benefit by makes a minor BC.
> 
> Both Ruby's Fiber and Lua's coroutine does not required a dedicate keyword.
> 
>> Looking at the current README, there are two issues that must be completely
>> solved IMO before accepting this:
>> 
>>> Each Fiber has a separate 4k stack. You can use the fiber.stack_size ini
>> option to change the default stack size. You can also use the second
>> argument of Fiber::__construct to set the stack size on fly.
>> 
>> Resizing of the stack should happen automatically, just like generators
>> resize automatically.
> 
> This size is the init stack size. It means when a Fiber created, it will get a
> dedicate stack of 4k size. When the fiber use all the stack space, zend vm 
> will
> allocate additional space for feature call frame, automatically.
> 
> The default size is 4k means that every fiber requires at least 4k memory to 
> use
> as there own stack. But user can change this by php.ini and the construct 
> argument
> to reduce the memory footprint.
> 
>> 
>>> Fiber::yield cannot be used in internal callback
>> 
>> This also seems problematic and will make fibers quite less useful,
>> especially as these yields can happen anywhere down the stack.
>> 
> 
> This do be a problem. But not so much big problem.
> 
> You cannot use Fiber::yield like
> 
> $f = new Fiber(function () {
>  array_map(function ($i) {
>    Fiber::yield($i);
>  }, [1, 2, 3]);
> });
> $f->resume();
> $f->resume();
> 
> Because when zend execute the array_map, it will push a new frame onto the c 
> stack.
> When zend execute Fiber::yield, it only backup it's php stack, and it's c 
> stack
> will be overwrites.
> 
> However, you can use Fiber::yield like
> 
> $f = new Fiber(function () {
>   Fiber::yield(1); // will cause by resume, by an internal callback
> });
> 
> ExtEventLoop::onRead($fd, function () { // this is an internal call
>   $f->resume();
> }); 
> 
>> Regards, Niklas
> 
> 
> 
> 
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: http://www.php.net/unsub.php




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to