搜尋
首頁後端開發php教程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 handlescurl_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\n	Host: www.baidu.com\r\n	Connection: keep-alive\r\n	Cache-Control: no-cache\r\n	Pragma: 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是完全不一样的。代码有些烂,还需要多看看文档,体会一下。

<?phpclass 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 := <-result	if 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 <- response	close(result)}

上面的几个方法,除了curl_multi_*貌似符合题意外(不确定,要看下源码),其他的方法都没有中断请求后recv()的操作, 如果得到response后还有后续操作,那么是有用的,否则并没有什么意义。想想可能是PHP操作粒度太大, 猜测用 C/C++ 应该能解决问题。

写的时候没有注意到一个问题,有些方式是返回值,有些直接打印了,这样不好,应该统一使用返回值得到请求结果。能力有限,先这样吧。

最后要做个广告, 计蒜客 是一家致力于计算机科学高端教育的公司,如果你对编程或者计算机底层有兴趣,不妨去他们网站学习学习。

同时,公司也一直在招人,如果你对自己的能力有信心,可以去试试。公司非常自由开放,90后为主。牛人也有不少,ACM世界冠军,知乎大牛。

公司主做教育,内部学习资料必须给力,我只看到了一些关于操作系统的测试题,涉及到的知识面很广,可见公司平均技术能力有多厉害。

如果文章中有疏漏,错误,还请大神们不吝指出,帮助菜鸟进步,谢谢。

原文  http://segmentfault.com/a/1190000004069411

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
在Laravel中使用Flash會話數據在Laravel中使用Flash會話數據Mar 12, 2025 pm 05:08 PM

Laravel使用其直觀的閃存方法簡化了處理臨時會話數據。這非常適合在您的應用程序中顯示簡短的消息,警報或通知。 默認情況下,數據僅針對後續請求: $請求 -

php中的捲曲:如何在REST API中使用PHP捲曲擴展php中的捲曲:如何在REST API中使用PHP捲曲擴展Mar 14, 2025 am 11:42 AM

PHP客戶端URL(curl)擴展是開發人員的強大工具,可以與遠程服務器和REST API無縫交互。通過利用Libcurl(備受尊敬的多協議文件傳輸庫),PHP curl促進了有效的執行

簡化的HTTP響應在Laravel測試中模擬了簡化的HTTP響應在Laravel測試中模擬了Mar 12, 2025 pm 05:09 PM

Laravel 提供简洁的 HTTP 响应模拟语法,简化了 HTTP 交互测试。这种方法显著减少了代码冗余,同时使您的测试模拟更直观。 基本实现提供了多种响应类型快捷方式: use Illuminate\Support\Facades\Http; Http::fake([ 'google.com' => 'Hello World', 'github.com' => ['foo' => 'bar'], 'forge.laravel.com' =>

在Codecanyon上的12個最佳PHP聊天腳本在Codecanyon上的12個最佳PHP聊天腳本Mar 13, 2025 pm 12:08 PM

您是否想為客戶最緊迫的問題提供實時的即時解決方案? 實時聊天使您可以與客戶進行實時對話,並立即解決他們的問題。它允許您為您的自定義提供更快的服務

解釋PHP中晚期靜態結合的概念。解釋PHP中晚期靜態結合的概念。Mar 21, 2025 pm 01:33 PM

文章討論了PHP 5.3中介紹的PHP中的晚期靜態結合(LSB),允許靜態方法的運行時間分辨率調用以更靈活的繼承。 LSB的實用應用和潛在的觸摸

PHP記錄:PHP日誌分析的最佳實踐PHP記錄:PHP日誌分析的最佳實踐Mar 10, 2025 pm 02:32 PM

PHP日誌記錄對於監視和調試Web應用程序以及捕獲關鍵事件,錯誤和運行時行為至關重要。它為系統性能提供了寶貴的見解,有助於識別問題並支持更快的故障排除

如何註冊和使用Laravel服務提供商如何註冊和使用Laravel服務提供商Mar 07, 2025 am 01:18 AM

Laravel的服務容器和服務提供商是其架構的基礎。 本文探討了服務容器,詳細信息服務提供商創建,註冊,並通過示例演示了實際用法。 我們將從OVE開始

自定義/擴展框架:如何添加自定義功能。自定義/擴展框架:如何添加自定義功能。Mar 28, 2025 pm 05:12 PM

本文討論了將自定義功能添加到框架上,專注於理解體系結構,識別擴展點以及集成和調試的最佳實踐。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
2 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
2 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。