> 2021年3月10日 上午2:58,Aaron Piotrowski <aa...@trowski.com> 写道:
> 
> 
>> On Mar 8, 2021, at 1:40 PM, Aaron Piotrowski <aa...@trowski.com> wrote:
>> 
>> Greetings everyone!
>> 
>> The vote has started on the fiber RFC: https://wiki.php.net/rfc/fibers 
>> <https://wiki.php.net/rfc/fibers>
>> 
>> Voting will run through March 22nd.
>> 
>> Cheers,
>> Aaron Piotrowski
> 
> Hi all!
> 
> A concern was raised off list that due to the complexity of the way this 
> feature interacts with the engine, it may be best to mark the feature as 
> experimental. This would allow some changes to be made to certain edge-case 
> behaviors and, while I don't think it would be necessary, the public API.
> 
> We (Niklas and I) agree with this and propose that if this feature is 
> accepted, it is marked as experimental through the 8.x release cycle or until 
> we're comfortable removing that label, whichever comes first.
> 
> Experimental in this context would mean fibers would be compiled and 
> available in all releases, but the documentation would denote that behavioral 
> and API changes may be made in future minor releases – use at your own risk.
> 
> As this feature is targeted at library authors and not average PHP users, we 
> believe there would be little effect to the community to take this step.
> 
> Cheers,
> Aaron Piotrowski
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
> 
> 

Sorry for being late, writing an English manuscript is still a bit difficult 
for me. Here I want to continue to express some of my views.

Firstly, I want to emphasize that the separate Fiber API has no meaning to 
users. Many people have a misunderstanding about this. They think that the 
Fiber feature can make PHP have the same high-performance network programming 
capabilities as Golang and support it blindly. There is a complete and complex 
system behind Goroutine. In terms of the amount of work implemented, the 
context switching capability, which is the capability provided by the ext-fiber 
extension, is only a very insignificant part.

In my opinion, Fiber is just an enhancement of Generator. As far as my 
superficial understanding is concerned, the evolution direction of amphp and 
reactphp should be similar to that of node.js. And node.js is not implemented 
with on any stacked-coroutines. In theory, the performance of 
stackless-coroutine is better. Furthermore, the implementation of await/async 
does not require stacked-coroutine. Therefore, I'm confused about the content 
of the Fiber proposal, because, it seems to put it in the wrong direction.

The implementation of the coroutine and the entire system are complementary and 
inseparable. With the optimization and update of the entire system, there will 
be more and more customization requirements, which influence the implementation 
details of the coroutine. This is also the reason why Swoole did not merge its 
coroutine capabilities into php-src, individually. As stripping out a separate 
coroutine extension, many customized things will lose their reason for 
existence. Therefore, we hope to incorporate the entire system, which will make 
everything more logical.

As Nikita said, if it is unnecessary, it is better to let the expansion stay in 
PECL, which will bring more freedom to the project and be more conducive to the 
rapid development of the project. Swoole has mastered all the technologies 
applied to ext-fiber in 2018 and built a complete network programming system 
based on coroutine. Since then, in order to better integrate with the original 
ecosystem of PHP, Swoole has coroutinefied PDO, mysqli, phpredis, libcurl, 
etc., and applied them to a large number of real-world projects. These projects 
also contributed to the development of the PHP coroutine technology and 
ecosystem. Of course, the Swoole community still expects to merge it into 
php-src at an appropriate time.

Therefore, I have to point out that there is no practical experience in the 
design of ext-fiber. It skips the progress, which to be a PECL extension, and 
does not have any guidance of practical application. This is very dangerous. 
The proposal regards the PHP kernel as a large test ground in the way that 
incorporating Fiber into php-src as an experimental feature. And one of the 
main reasons is simply that the installation of extensions is difficult for 
some users. For many years, I have always thought that the PHP kernel's 
attitude towards merging anything is scientific and rigorous, so I have always 
been cautious and respectful. But this time, it makes me confused and a little 
bit disappointed.

In various design details, there are still many questions that make me 
confused. I will point out a few here:

1. Fiber class should not be designed as final

We should try to avoid any internal class being designed as final unless there 
are any necessary security reasons, otherwise, the scalability of the class 
will be greatly restricted. For instance, in practice, we usually assign a 
Context for every Fiber, it seems like $GLOBALS, so that we can write like this

    class MyFiber extends \Fiber {
        public $context = [];
    }

Or, we can add a custom log for the switch of the coroutine, or switch some 
contexts we want to switch

    class MyFiber extends \Fiber {
        public function resume(...$data):mixed {
            log('resume to {$this->getId()}');
            return parent::resume($data);
        }
    }

There are also some coroutine frameworks that want to track and count the 
coroutines created by users and will perform some injection operations, so they 
have their own special version of the coroutine implementation. If inheritance 
is not possible, then we need twice the number of objects, and mounting Fiber 
as a property on the newly implemented class. It is bad for performance and 
very inelegant.

If ext-fiber is declared as final for technical reasons, then I can only say 
that this is a technically problematic implementation.

2. Coroutine state acquisition problem

The ext-fiber defines many methods to obtain the state of the coroutine, such 
as isRunning(), etc. Why not directly export the status constants and provide a 
getStatus() function, if we just want the simplest implementation?

If there are some internal states on the status, then these states should be 
distinguishable. For example, they can be removed by bit operations or stored 
on other attributes.


The following are some technical issues about the implementation of ext-fiber. 
Due to the limited time, I have only read part of the source code limitedly. 
Excuse me, if there are any inaccuracies.

1. The code about coroutine switching could be simplified

There is essentially only one kind of switch API for coroutines that is 
resume(), in boost it called jump(). Its function is to switch to a coroutine, 
and yield()/suspend() is equivalent to $previousCoroutine->resume(). So I can’t 
understand why resume() and suspend() are implemented twice in the 
implementation of ext-fiber.

If we indicate the correct implementation of suspend() in PHP, it should look 
like this:

    public static function suspend(...$data): mixed
    {
        return static::this()->getPrevious()->resume(...$data);
    }

If there are any technical reasons for implementing resume() twice in 
ext-fiber, then I can only say that this is still a wrong implementation.

2. Switch notification

In zend_fiber_switch_to(), call zend_observer_fiber_switch_notify() twice at 
the beginning and ending of switch is an obviously wrong implementation. After 
we solve the previous problem, we only need to notify once before switching, 
because the second notification will be sent by another coroutine before it's 
switching back.

Other issues

1. C extension support

This Fiber proposal is dedicated to providing PHP with coroutine capabilities, 
but it does not consider the C extension. For example, it can consider turning 
some APIs into function pointers so that other extensions can add some content.

2. Unsolvable blocking

The Fiber proposal mentions the blocking problem but does not give a good idea 
or solution to solve it. In the coroutine system, no blocking is allowed. 
Blocking will greatly affect the normal operation of the entire program. Unlike 
JavaScript, PHP is not a naturally asynchronous language. Implementing 
coroutines and EventLoop in the user space can only solve some blocking from 
network calls, but other blocking problems such as file reading and writing, 
DNS queries, etc., can hardly be solved. However, PHP is very similar to 
node.js, which is more suitable for the 'multi-process with single-thread' 
model. Therefore, integrating libuv and tightly combining with coroutine 
features to achieve a complete coroutine system is a good asynchronous network 
IO solution.

3. CPU starvation

The capability of the 'multi-process with single-thread' model in CPU 
scheduling is not that good as Golang's multi-thread model. Solving the CPU 
starvation problem is another issue that needs to be considered

For example, in Swow (https://github.com/swow/swow, the latest research result 
of the Swoole community), the WatchDog component based on the monitoring the 
number of coroutine switching rounds and the interrupt feature of ZendVM solves 
this problem. It can issue an alarm when the CPU starvation occurs. Through 
configuration or PHP programming, it can also actively suspend the coroutine 
when the CPU starvation occurs, restore the average response speed of the 
entire program, and even directly kill the coroutine when the CPU infinite loop 
occurs.

4. Pure C coroutine

The Fiber proposal never mentions the support for pure C coroutines. In Swow, 
the event scheduler is a pure C function and does not need a PHP stack. It only 
needs to switch the C stack when switching to other coroutines and its 
switching performance is almost double that of PHP, because, in such a 
coroutine system, most exchanges occur between the scheduler and other 
coroutines.

5. Not compatible with Swoole

In my opinion, Swoole is an important part of the PHP ecosystem. But now, Fiber 
cannot work with Swoole. And based on the above reasons, Swoole will not 
consider compatible fiber.

We would expect some ZendAPI rather than Fiber extensions to provide support 
for coroutine switching.

6. Boost-context is not used on the Windows

The performance of win-fiber is far inferior to boost-context. I can not find 
any reason to use win-fiber instead of boost-context in Windows.

The Swow extension uses boost-context on all platforms and has been actively 
tested (https://github.com/swow/swow/runs/2053921797). CI will also automate 
execute nightly build and release DLL (https://github.com/swow/swow/releases), 
and there is no issue so far.

Also, there are many fragmentary issues. Due to limited time, I cannot write 
them all at once.

Of course, some designs of ext-fiber still refresh me, such as using Reflection 
to get coroutine status (in Swoole, we just keep adding methods to the 
coroutine class). Nevertheless, I don’t know what the benefits of using 
Reflection to get these states are.

I'm not particularly satisfied with all aspects of ext-fiber's overall plan and 
C code implementation, so I have to point them out here.

Regards,
Twosee

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

Reply via email to