Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:101814 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 9259 invoked from network); 9 Feb 2018 00:13:00 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 9 Feb 2018 00:13:00 -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 184.105.206.29 cause and error) X-PHP-List-Original-Sender: i@lvht.net X-Host-Fingerprint: 184.105.206.29 smtpbg202.qq.com Linux 2.5 (sometimes 2.4) (4) Received: from [184.105.206.29] ([184.105.206.29:46309] helo=smtpbg202.qq.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id E9/03-21403-A87EC7A5 for ; Thu, 08 Feb 2018 19:12:59 -0500 X-QQ-mid: bizesmtp8t1518135170tkc6djpnp Received: from [192.168.1.4] (unknown [222.71.123.232]) by esmtp4.qq.com (ESMTP) with id ; Fri, 09 Feb 2018 08:12:49 +0800 (CST) X-QQ-SSF: 0110000000400060F750B00A0000000 X-QQ-FEAT: Euuz9Hb9fOGghSb7qS6QVSphK+EpVA7LJbXkk472jw3BzryDWXWdp+rX8U+yI RXl7rLI6/NnSgPX5lAnivGfQ/wNzuDlCKK7jZ+6TrAUAuYOUIWOCnivEfI1TNi53q3S+p9k oKfEZTbZvSZwpurpIKecq8Wl+N+3PuxjOyqwPFF1ZavM6pCkI5q0maYgdqs1TyL4893zxHw Aymch0ENWLdZqx6zDFlYm+7PRHE9fRCc/V6zl/NkXwYzAYlremtj7kYzZy2t/Eg6/JiCsjS FvqaTCRg6oupk7 X-QQ-GoodBg: 0 Content-Type: text/plain; charset=us-ascii Mime-Version: 1.0 (Mac OS X Mail 11.3 \(3445.6.9\)) In-Reply-To: Date: Fri, 9 Feb 2018 08:12:49 +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.9) 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) > 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. 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? >=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? 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 =3D Fiber::yield(...); if ($a =3D=3D=3D false) { throw new Exception(...); } 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. 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 =3D false; return $this->coroutine->current(); } else { $retval =3D $this->coroutine->send($this->sendValue); $this->sendValue =3D null; return $retval; =20 } =20 } It is verbose. See = https://nikic.github.io/2012/12/22/Cooperative-multitasking-using-coroutin= es-in-PHP.html >=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. 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: >=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. 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. >=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 This do be a problem. But not so much big problem. You cannot use Fiber::yield like $f =3D 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 =3D 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(); });=20 > Regards, Niklas