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