前言我对php异步的认识还是比较混乱的。写这篇文章是为了整理一下,可能有错误。在传统的php-fpm中,一个进程执行一个请求,需要产生多少个进程才能实现并发。更糟糕的是每次请求都需要重新编译执行,导致并发失败。因此,出现了两个国内流行的常驻内存框架Swoole和WorkerMan[1]。这两个框架的原理都是通过事件循环,让程序驻留在内存中等待外部请求来实现高并发。为什么需要异步?我们先来看一个例子。在工作目录中创建一个新文件slowServer.php计数=1;//只开启一个Process$http_worker->onMessage=function($connection,$host){echo1;$data=file_get_contents('http://localhost:8081');$connection->send($data);};Worker::runAll();启动服务器phpworker.phpstart在浏览器中打开两个选项卡,都打开URLhttp://localhost:8082。这时候可以看到终端输出了“1”,过了一会儿又输出了“1”。原因是8081服务器在处理第一个请求时阻塞在等待8081返回。开始处理第二个请求。也就是说请求一个一个执行,需要建立多少个进程才能达到php-fpm那么多的并发。现在修改代码$http_worker->onMessage=function($connection,$host){echo1;$loop=Worker::getEventLoop();$client=new\React\HttpClient\Client($loop);$request=$client->request('GET','http://localhost:8081');$request->on('error',function(Exception$e)use($connection){$connection->send($e);});$request->on('response',function($response)use($connection){$response->on('data',function($data)use($connection){$connection->send($data);});});$请求->结束();};现在打开服务,然后在浏览器发起一个请求,发现请求后马上输出了第二个“1”,而此时第一个请求还没有结束。这意味着进程不再阻塞,并发量取决于cpu和内存,而不是进程数。从上面的例子中可以清楚地看出为什么需要异步。reactphp框架通过让http请求异步,让onMessage函数成为非阻塞的,cpu可以处理下一个请求。即等待8081从cpu循环返回变成epoll等待。异步的意义在于将cpu从io等待中解放出来,去处理其他的计算任务。如果你想知道如何使用框架实现异步,就看这里。WorkerMan配合ReactPHP或者自带的AsyncTcpConnection已经可以满足很多io请求的异步需求了。让我们继续讨论这些框架是如何异步的。哪些地方应该做成异步通过上面的例子我们已经知道,一旦执行不需要cpu,但是在等待io的时候,io过程应该做成异步。上面实现事件循环的例子就是通过reactphp把http请求变成异步的。事实上,WorkerMan框架本身也是异步的。让我们看看WorkerMan如何启用onMessage函数来异步接受请求。首先创建以下文件//注册一个fd(文件描述符)函数react($socket){$new_socket=stream_socket_accept($socket,0,$remote_address);echo1;}$eventBase=newEventBase();$event=newEvent($eventBase,$socket,Event::READ|Event::PERSIST,'react',$socket);//注册一个事件,检测fd是否写入内容$event->add();$eventBase->loop();//开始循环,开始执行$phpreact.php在另一个终端执行telnet127.0.0.18081,然后你会看到第一个终端输出'1'。之前写过一篇文章《php使用epoll》,是这篇文章的基础。在那篇文章中,事件回调是通过计时实现的,即$event->add($seconds);而这里的事件回调是通过检测fd是否有写入内容来实现的,这个过程不需要CPU参与。当fd有内容写入时,会调用函数'react',此时会使用cpu。如果此时进程执行另一个异步请求,比如用reactphp框架请求一个网页,那么程序就会让出cpu,如果此时有另一个请求进来,它可以回调执行另一个'react'功能。这增加了并发性。CoroutinegeneratorGenerator这是生成器的官方PHP文档http://php.net/manual/zh/lang...
