日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > php >内容正文

php

PHP编程中的并发

發布時間:2025/1/21 php 85 豆豆
生活随笔 收集整理的這篇文章主要介紹了 PHP编程中的并发 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

PHP編程中的并發

周末去北京面了兩個公司,認識了幾位技術牛人,面試中聊了很多,感覺收獲頗豐。認識到了自己的不足之處,也堅定了自己對計算機學習的信心。本文是對其中一道面試題的總結。

面試中有一個問題沒有很好的回答出來,題目為:并發3個http請求,只要其中一個請求有結果,就返回,并中斷其他兩個。

當時考慮的內容有些偏離題目原意, 一直在考慮如何中斷http請求,大概是在 client->recv() 之前去判斷結果是否已經產生,所以回答的是用 socket 去發送一個 http 請求,把 socket 加入 libevent 循環監聽,在callback中判斷是否已經得到結果,如果已經得到結果,就直接 return。

后來自己越說越覺得不對,既然已經recv到結果,就不能算是中斷http請求。何況自己從來沒用過libevent。后來說了還說了兩種實現,一個是用 curl_multi_init, 另一個是用golang實現并發。
golang的版本當時忘了close的用法,結果并不太符合題意。

這題沒答上來,考官也沒為難我。但是心里一直在考慮,直到面試完走到樓下有點明白什么意思了,可能考的是并發,進程線程的應用。所以總結了這篇文章,來講講PHP中的并發。
本文大約總結了PHP編程中的五種并發方式,最后的Golang的實現純屬無聊,可以無視。如果有空,會再補充一個libevent的版本。

curl_multi_init

文檔中說的是 Allows the processing of multiple cURL handles asynchronously. 確實是異步。這里需要理解的是select這個方法,文檔中是這么解釋的Blocks until there is activity on any of the curl_multi connections.。了解一下常見的異步模型就應該能理解,select, epoll,都很有名,這里引用一篇非常好的文章,有興趣看下解釋吧。

<?php // build the individual requests as above, but do not execute them $ch_1 = curl_init('http://www.baidu.com/'); $ch_2 = curl_init('http://www.baidu.com/'); curl_setopt($ch_1, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch_2, CURLOPT_RETURNTRANSFER, true);// build the multi-curl handle, adding both $ch $mh = curl_multi_init(); curl_multi_add_handle($mh, $ch_1); curl_multi_add_handle($mh, $ch_2);// execute all queries simultaneously, and continue when all are complete $running = null; do {curl_multi_exec($mh, $running);$ch = curl_multi_select($mh);if($ch !== 0){$info = curl_multi_info_read($mh);if($info){var_dump($info);$response_1 = curl_multi_getcontent($info['handle']);echo "$response_1 \n";break;}} } while ($running > 0);//close the handles curl_multi_remove_handle($mh, $ch_1); curl_multi_remove_handle($mh, $ch_2); curl_multi_close($mh);

這里我設置的是,select得到結果,就退出循環,并且刪除 curl resource, 從而達到取消http請求的目的。

swoole_client

swoole_client提供了異步模式,我竟然把這個忘了。這里的sleep方法需要swoole版本大于等于1.7.21, 我還沒升到這個版本,所以直接exit也可以。

<?php $client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC); //設置事件回調函數 $client->on("connect", function($cli) {$req = "GET / HTTP/1.1\r\nHost: www.baidu.com\r\nConnection: keep-alive\r\nCache-Control: no-cache\r\nPragma: no-cache\r\n\r\n";for ($i=0; $i < 3; $i++) {$cli->send($req);} }); $client->on("receive", function($cli, $data){echo "Received: ".$data."\n";exit(0);$cli->sleep(); // swoole >= 1.7.21 }); $client->on("error", function($cli){echo "Connect failed\n"; }); $client->on("close", function($cli){echo "Connection close\n"; }); //發起網絡連接 $client->connect('183.207.95.145', 80, 1);

process

哎,竟然忘了 swoole_process, 這里就不用 pcntl 模塊了。但是寫完發現,這其實也不算是中斷請求,而是哪個先到讀哪個,忽視后面的返回值。

<?php$workers = []; $worker_num = 3;//創建的進程數 $finished = false; $lock = new swoole_lock(SWOOLE_MUTEX);for($i=0;$i<$worker_num ; $i++){$process = new swoole_process('process');//$process->useQueue();$pid = $process->start();$workers[$pid] = $process; }foreach($workers as $pid => $process){//子進程也會包含此事件swoole_event_add($process->pipe, function ($pipe) use($process, $lock, &$finished) {$lock->lock();if(!$finished){$finished = true;$data = $process->read();echo "RECV: " . $data.PHP_EOL;}$lock->unlock();}); }function process(swoole_process $process){$response = 'http response';$process->write($response);echo $process->pid,"\t",$process->callback .PHP_EOL; }for($i = 0; $i < $worker_num; $i++) {$ret = swoole_process::wait();$pid = $ret['pid'];echo "Worker Exit, PID=".$pid.PHP_EOL; }

pthreads

編譯pthreads模塊時,提示php編譯時必須打開ZTS, 所以貌似必須 thread safe 版本才能使用. wamp中多php正好是TS的,直接下了個dll, 文檔中的說明復制到對應目錄,就在win下測試了。 還沒完全理解,查到文章說 php 的 pthreads 和 POSIX pthreads是完全不一樣的。代碼有些爛,還需要多看看文檔,體會一下。

<?php class Foo extends Stackable {public $url;public $response = null;public function __construct(){$this->url = 'http://www.baidu.com';}public function run(){} }class Process extends Worker {private $text = "";public function __construct($text,$object){$this->text = $text;$this->object = $object;}public function run(){while (is_null($this->object->response)){print " Thread {$this->text} is running\n";$this->object->response = 'http response';sleep(1);}} }$foo = new Foo();$a = new Process("A",$foo); $a->start();$b = new Process("B",$foo); $b->start();echo $foo->response;

yield

yield生成的generator,可以中斷函數,并用send向 generator 發送消息。
稍后補充協程的版本。還在學習中。

Golang

用Go實現比較簡單, 回家后查了查 close,處理一下 panic就ok了。代碼如下:

package mainimport ("fmt" )func main() {var result chan string = make(chan string, 1)for index := 0; index< 3; index++ {go doRequest(result)}res, ok := <-resultif ok {fmt.Println("received ", res)}}func doRequest(result chan string) {response := "http response"defer func() {if x := recover(); x != nil {fmt.Println("Unable to send: %v", x)}}()result <- responseclose(result) }

上面的幾個方法,除了 curl_multi_* 貌似符合題意外(不確定,要看下源碼),其他的方法都沒有中斷請求后recv()的操作, 如果得到response后還有后續操作,那么是有用的,否則并沒有什么意義。想想可能是PHP操作粒度太大, 猜測用 C/C++ 應該能解決問題。

寫的時候沒有注意到一個問題,有些方式是返回值,有些直接打印了,這樣不好,應該統一使用返回值得到請求結果。能力有限,先這樣吧。

最后要做個廣告,計蒜客是一家致力于計算機科學高端教育的公司,如果你對編程或者計算機底層有興趣,不妨去他們網站學習學習。
同時,公司也一直在招人,如果你對自己的能力有信心,可以去試試。公司非常自由開放,90后為主。牛人也有不少,ACM世界冠軍,知乎大牛。
公司主做教育,內部學習資料必須給力,我只看到了一些關于操作系統的測試題,涉及到的知識面很廣,可見公司平均技術能力有多厲害。

如果文章中有疏漏,錯誤,還請大神們不吝指出,幫助菜鳥進步,謝謝。

總結

以上是生活随笔為你收集整理的PHP编程中的并发的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。