摘要:編程中的并發周末去北京面了兩個公司,認識了幾位技術牛人,面試中聊了很多,感覺收獲頗豐。本文大約總結了編程中的五種并發方式,最后的的實現純屬無聊,可以無視。生成的可以中斷函數,并用向發送消息。
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的版本。
文檔中說的是 Allows the processing of multiple cURL handles asynchronously. 確實是異步。這里需要理解的是select這個方法,文檔中是這么解釋的Blocks until there is activity on any of the curl_multi connections.。了解一下常見的異步模型就應該能理解,select, epoll,都很有名,這里引用一篇非常好的文章,有興趣看下解釋吧。
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_clientswoole_client提供了異步模式,我竟然把這個忘了。這里的sleep方法需要swoole版本大于等于1.7.21, 我還沒升到這個版本,所以直接exit也可以。
on("connect", function($cli) { $req = "GET / HTTP/1.1 Host: www.baidu.com Connection: keep-alive Cache-Control: no-cache Pragma: no-cache "; for ($i=0; $i < 3; $i++) { $cli->send($req); } }); $client->on("receive", function($cli, $data){ echo "Received: ".$data." "; exit(0); $cli->sleep(); // swoole >= 1.7.21 }); $client->on("error", function($cli){ echo "Connect failed "; }); $client->on("close", function($cli){ echo "Connection close "; }); //發起網絡連接 $client->connect("183.207.95.145", 80, 1);process
哎,竟然忘了 swoole_process, 這里就不用 pcntl 模塊了。但是寫完發現,這其實也不算是中斷請求,而是哪個先到讀哪個,忽視后面的返回值。
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," ",$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是完全不一樣的。代碼有些爛,還需要多看看文檔,體會一下。
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 "; $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 發送消息。
稍后補充協程的版本。還在學習中。
用Go實現比較簡單, 回家后查了查 close,處理一下 panic就ok了。代碼如下:
package main import ( "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://specialneedsforspecialkids.com/yun/21254.html
摘要:下文如無特殊聲明將使用進程同時表示進程線程。收到數據后服務器程序進行處理然后使用向客戶端發送響應。現在各種高并發異步的服務器程序都是基于實現的,比如。 并發 IO 問題一直是服務器端編程中的技術難題,從最早的同步阻塞直接 Fork 進程,到 Worker 進程池/線程池,到現在的異步IO、協程。PHP 程序員因為有強大的 LAMP 框架,對這類底層方面的知識知之甚少,本文目的就是詳細介...
摘要:為語言提供了強大的協程編程模式。提供的協程語法借鑒自,在此向開發組致敬協程可以與很好地互補。并發執行使用創建協程,可以讓和兩個函數變成并發執行。協程需要拿到請求的結果。 Swoole4為PHP語言提供了強大的CSP協程編程模式。底層提供了3個關鍵詞,可以方便地實現各類功能。 Swoole4提供的PHP協程語法借鑒自Golang,在此向GO開發組致敬 PHP+Swoole協程可以與...
摘要:現在在后端業務開發編程方面,技術力量強的團隊已經開始將技術棧從同步模式切換為異步了。使用這些技術方案是無法兼容已有程序的。影響了異步回調技術棧的普及。將會成為未來后端開發領域的主流技術方案。 今天太忙,少寫一點,后面再補充。 異步模式 Go 語言越來越熱門,很多大型互聯網公司后端正在轉向 GO 。Java 圈知名的服務化框架 Dubbo 也宣布轉型異步模式。這是一個大趨勢,異步模式已經...
閱讀 2083·2023-04-26 02:41
閱讀 2146·2021-09-24 09:47
閱讀 1546·2019-08-30 15:53
閱讀 1205·2019-08-30 13:01
閱讀 1885·2019-08-29 11:27
閱讀 2857·2019-08-28 17:55
閱讀 1740·2019-08-26 14:00
閱讀 3377·2019-08-26 10:18