Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:101819 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 92215 invoked from network); 10 Feb 2018 09:56:45 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 10 Feb 2018 09:56:45 -0000 Authentication-Results: pb1.pair.com header.from=i@lvht.net; sender-id=unknown Authentication-Results: pb1.pair.com smtp.mail=i@lvht.net; spf=permerror; sender-id=unknown Received-SPF: error (pb1.pair.com: domain lvht.net from 54.207.22.56 cause and error) X-PHP-List-Original-Sender: i@lvht.net X-Host-Fingerprint: 54.207.22.56 smtpbgbr2.qq.com Received: from [54.207.22.56] ([54.207.22.56:40679] helo=smtpbgbr2.qq.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id D8/09-21403-9D1CE7A5 for ; Sat, 10 Feb 2018 04:56:42 -0500 X-QQ-mid: bizesmtp13t1518256591tyf0q0zq Received: from [192.168.1.4] (unknown [222.71.123.232]) by esmtp4.qq.com (ESMTP) with id ; Sat, 10 Feb 2018 17:56:30 +0800 (CST) X-QQ-SSF: 0110000000400070F850000A0000000 X-QQ-FEAT: Euuz9Hb9fOGXtFYOqwYQcjVfWXT03TBfAkLvOSPp5yW5jXl5LoT4Za+2i4xnM unOHYX2YPiTAPsNAimximOxwoCDE73i6DKkaUfgHlxo1cY/rTBPB7R8Tn+a59KlMMGow5BW vXIX4xmvvegjLToasZk0X0MarcEi6ApEj1ykaOx9ooEPLDFY34k0gxtcKp3aqpXrqB9uwpj NRhLtMRsOpwcYutPXyxhPD549cL/A4TiNtb1JBEoRhU8VPIQ7WP9Yth8st11Y8C2SPcYchx F2blgj0ngI1bE5dGru95+Ul9Q= X-QQ-GoodBg: 0 Content-Type: text/plain; charset=us-ascii Mime-Version: 1.0 (Mac OS X Mail 11.3 \(3445.6.10\)) In-Reply-To: Date: Sat, 10 Feb 2018 17:56:30 +0800 Cc: Aaron Piotrowski , PHP Internals , Dmitry Stogov Content-Transfer-Encoding: quoted-printable Message-ID: References: <76EBF900-3BE8-4B60-9422-880A9754FCC4@lvht.net> <0DDFDACA-6322-461C-9D57-215E8C7D9CD0@trowski.com> To: Niklas Keller X-Mailer: Apple Mail (2.3445.6.10) X-QQ-SENDSIZE: 520 Feedback-ID: bizesmtp:lvht.net:qybgforeign:qybgforeign4 X-QQ-Bgrelay: 1 Subject: Re: [PHP-DEV] [RFC] Fiber support (again) From: i@lvht.net (Haitao Lv) 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 wrote: >=20 >>=20 >> On Feb 9, 2018, at 06:22, Niklas Keller wrote: >>=20 >>>=20 >>>> - 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() >>>=20 >>> 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. >>=20 >>=20 >> The language should offer a sane API, not the absolute minimum = required to >> work for these things. >=20 > 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. >=20 > So do we really need to offer three additional helper method? Or what = is your > advice about these API? >=20 >>=20 >>>> - What about throwing exceptions into a fiber? >>>=20 >>> 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. >>=20 >>=20 >> And throw the exception where? That means async code with fibers = can't >> really handle errors? >=20 > 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. >=20 > 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, >=20 > $a =3D Fiber::yield(...); > if ($a =3D=3D=3D false) { > throw new Exception(...); > } >=20 > And both the Ruby and Lua does not offer such API as well. >>=20 >>>=20 >>>>=20 >>>> - 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). >>>=20 >>> All Fiber created with a suspended status. So make resume to do both = the >>> init and resume >>> do make sense. >>>=20 >>=20 >> 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. >=20 > 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. >=20 > 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 >=20 > function run() { > if ($this->beforeFirstYield) { > $this->beforeFirstYield =3D false; > return $this->coroutine->current(); > } else { > $retval =3D $this->coroutine->send($this->sendValue); > $this->sendValue =3D null; > return $retval; =20 > } =20 > } >=20 > It is verbose. >=20 > See = https://nikic.github.io/2012/12/22/Cooperative-multitasking-using-coroutin= es-in-PHP.html >=20 >>=20 >>> Please see Ruby Fiber API = https://ruby-doc.org/core-2.2.0/Fiber.html. >>>=20 >>>>=20 >>>> - What happens if the sub1() function in the RFC is invoked outside = of a >>> fiber? >>>=20 >>> You will get a Fatal Error like >>> Fatal error: Uncaught Error: Cannot call Fiber::yield out of Fiber >>>=20 >>>> - 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. >>>=20 >>> 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. >>=20 >>=20 >> Right, if it's a standalone extension it can't use a new keyword, but = as a >> language feature it totally can. >=20 > 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. >=20 > Both Ruby's Fiber and Lua's coroutine does not required a dedicate = keyword. >=20 >> Looking at the current README, there are two issues that must be = completely >> solved IMO before accepting this: >>=20 >>> 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. >>=20 >> Resizing of the stack should happen automatically, just like = generators >> resize automatically. >=20 > 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. >=20 > 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. >=20 >>=20 >>> Fiber::yield cannot be used in internal callback >>=20 >> This also seems problematic and will make fibers quite less useful, >> especially as these yields can happen anywhere down the stack. >>=20 >=20 > This do be a problem. But not so much big problem. >=20 > You cannot use Fiber::yield like >=20 > $f =3D new Fiber(function () { > array_map(function ($i) { > Fiber::yield($i); > }, [1, 2, 3]); > }); > $f->resume(); > $f->resume(); >=20 > 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. >=20 > However, you can use Fiber::yield like >=20 > $f =3D new Fiber(function () { > Fiber::yield(1); // will cause by resume, by an internal callback > }); >=20 > ExtEventLoop::onRead($fd, function () { // this is an internal call > $f->resume(); > });=20 >=20 >> Regards, Niklas >=20 >=20 >=20 >=20 > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php