摘要:面試中有一個(gè)問題沒有很好的回答出來,題目為并發(fā)個(gè)請(qǐng)求,只要其中一個(gè)請(qǐng)求有結(jié)果,就返回,并中斷其他兩個(gè)。后來說了還說了兩種實(shí)現(xiàn),一個(gè)是用另一個(gè)是用實(shí)現(xiàn)并發(fā)。所以總結(jié)了這篇文章,來講講中的并發(fā)。生成的可以中斷函數(shù),并用向發(fā)送消息。
面試中有一個(gè)問題沒有很好的回答出來,題目為:并發(fā)3個(gè)http請(qǐng)求,只要其中一個(gè)請(qǐng)求有結(jié)果,就返回,并中斷其他兩個(gè)。
當(dāng)時(shí)考慮的內(nèi)容有些偏離題目原意, 一直在考慮如何中斷http請(qǐng)求,大概是在 client->recv() 之前去判斷結(jié)果是否已經(jīng)產(chǎn)生,所以回答的是用 socket 去發(fā)送一個(gè) http 請(qǐng)求,把 socket 加入 libevent 循環(huán)監(jiān)聽,在callback中判斷是否已經(jīng)得到結(jié)果,如果已經(jīng)得到結(jié)果,就直接 return。
后來自己越說越覺得不對(duì),既然已經(jīng)recv到結(jié)果,就不能算是中斷http請(qǐng)求。何況自己從來沒用過libevent。后來說了還說了兩種實(shí)現(xiàn),一個(gè)是用 curl_multi_init, 另一個(gè)是用golang實(shí)現(xiàn)并發(fā)。
golang的版本當(dāng)時(shí)忘了close的用法,結(jié)果并不太符合題意。
這題沒答上來,考官也沒為難我。但是心里一直在考慮,直到面試完走到樓下有點(diǎn)明白什么意思了,可能考的是并發(fā),進(jìn)程線程的應(yīng)用。所以總結(jié)了這篇文章,來講講PHP中的并發(fā)。本文大約總結(jié)了PHP編程中的五種并發(fā)方式,最后的Golang的實(shí)現(xiàn)純屬無聊,可以無視。如果有空,會(huì)再補(bǔ)充一個(gè)libevent的版本。
curl_multi_init
文檔中說的是 Allows the processing of multiple cURL handles asynchronously. 確實(shí)是異步。這里需要理解的是select這個(gè)方法,文檔中是這么解釋的Blocks until there is activity on any of the curl_multi connections.。了解一下常見的異步模型就應(yīng)該能理解,select, epoll,都很有名,這里引用一篇非常好的文章,有興趣看下解釋吧。
// 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 "; 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);
這里我設(shè)置的是,select得到結(jié)果,就退出循環(huán),并且刪除 curl resource, 從而達(dá)到取消http請(qǐng)求的目的。
swoole_client
swoole_client提供了異步模式,我竟然把這個(gè)忘了。這里的sleep方法需要swoole版本大于等于1.7.21, 我還沒升到這個(gè)版本,所以直接exit也可以。
$client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC);
//設(shè)置事件回調(diào)函數(shù)
$client->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 ";
});
//發(fā)起網(wǎng)絡(luò)連接
$client->connect("183.207.95.145", 80, 1);
process
哎,竟然忘了 swoole_process, 這里就不用 pcntl 模塊了。但是寫完發(fā)現(xiàn),這其實(shí)也不算是中斷請(qǐng)求,而是哪個(gè)先到讀哪個(gè),忽視后面的返回值。
$workers = [];
$worker_num = 3;//創(chuàng)建的進(jìn)程數(shù)
$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){
//子進(jìn)程也會(huì)包含此事件 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模塊時(shí),提示php編譯時(shí)必須打開ZTS, 所以貌似必須 thread safe 版本才能使用. wamp中多php正好是TS的,直接下了個(gè)dll, 文檔中的說明復(fù)制到對(duì)應(yīng)目錄,就在win下測試了。 還沒完全理解,查到文章說 php 的 pthreads 和 POSIX pthreads是完全不一樣的。代碼有些爛,還需要多看看文檔,體會(huì)一下。
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 "; $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,可以中斷函數(shù),并用send向 generator 發(fā)送消息。稍后補(bǔ)充協(xié)程的版本。還在學(xué)習(xí)中。
Golang
用Go實(shí)現(xiàn)比較簡單, 回家后查了查 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)
}
上面的幾個(gè)方法,除了 curl_multi_* 貌似符合題意外(不確定,要看下源碼),其他的方法都沒有中斷請(qǐng)求后recv()的操作, 如果得到response后還有后續(xù)操作,那么是有用的,否則并沒有什么意義。想想可能是PHP操作粒度太大, 猜測用 C/C++ 應(yīng)該能解決問題。
寫的時(shí)候沒有注意到一個(gè)問題,有些方式是返回值,有些直接打印了,這樣不好,應(yīng)該統(tǒng)一使用返回值得到請(qǐng)求結(jié)果。能力有限,先這樣吧。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/22786.html
摘要:這里呢,我直接給出高并發(fā)場景通常都會(huì)考慮的一些解決思路和手段結(jié)尾如何有效的準(zhǔn)備面試中并發(fā)類問題,我已經(jīng)給出我的理解。 showImg(https://segmentfault.com/img/bV7Viy?w=550&h=405); 主題 又到面試季了,從群里,看到許多同學(xué)分享了自己的面試題目,我也抽空在網(wǎng)上搜索了一些許多公司使用的面試題,目前校招和社招的面試題基本都集中在幾個(gè)大方向上...
摘要:并發(fā)表示在一段時(shí)間內(nèi)有多個(gè)動(dòng)作存在。并發(fā)帶來的問題在享受并發(fā)編程帶來的高性能高吞吐量的同時(shí),也會(huì)因?yàn)椴l(fā)編程帶來一些意想不到弊端。并發(fā)過程中多線程之間的切換調(diào)度,上下文的保存恢復(fù)等都會(huì)帶來額外的線程切換開銷。 0x01 什么是并發(fā) 要理解并發(fā)首選我們來區(qū)分下并發(fā)和并行的概念。 并發(fā):表示在一段時(shí)間內(nèi)有多個(gè)動(dòng)作存在。 并行:表示在同一時(shí)間點(diǎn)有多個(gè)動(dòng)作同時(shí)存在。 例如:此刻我正在寫博客,但...
摘要:我思考的是什么才算是高并發(fā)你一天幾個(gè)肯定高不了。所以我得出一個(gè)自定義概念如果某個(gè)系統(tǒng)的日在千萬級(jí)別以上,他就可能是一個(gè)高并發(fā)的系統(tǒng)。高并發(fā)的問題,我們具體該關(guān)心什么講真話,高并發(fā)是個(gè)比較抽象的概念。是指秒鐘響應(yīng)的請(qǐng)求數(shù)量。 這并不是一個(gè)回答的問題的文章,而是由此引發(fā)的一個(gè)思考。 大家心里仔細(xì)想想,當(dāng)你們聽到高并發(fā)網(wǎng)站時(shí),心里對(duì)這個(gè)網(wǎng)站是個(gè)什么概念?首先想到的是淘寶嗎?帶著問題,我們一起...
摘要:并發(fā)同步控制遇到并發(fā)時(shí),我們避免不了要談并發(fā)控制。它會(huì)阻塞其它的線程執(zhí)行,如果當(dāng)前線程一直持有的監(jiān)控鎖,就會(huì)把其它線程一直阻塞下去。如果此時(shí)線程和線程同時(shí)進(jìn)入方法,用一段語言描述方法的執(zhí)行過程,可能是這樣子。 并發(fā)同步控制 遇到并發(fā)時(shí),我們避免不了要談并發(fā)控制。在Java語言中,我們談并發(fā)時(shí),要談到Object的監(jiān)控鎖。在MySQL的數(shù)據(jù)庫并發(fā)中,我們也要談到mysql的鎖機(jī)制。 這樣...
摘要:而爬蟲一般用多線程來控制并發(fā),然而如果是爬蟲,由于其單線程無阻塞性質(zhì)以及事件循環(huán)機(jī)制,一般不用多線程來控制并發(fā)當(dāng)然也可以實(shí)現(xiàn)多線程,此處非重點(diǎn)不再多講,而是更加簡便地直接在代碼層級(jí)上實(shí)現(xiàn)并發(fā)。下面我們用行代碼實(shí)現(xiàn)一個(gè)并發(fā)控制的函數(shù)。 前言 首發(fā)于 github blog 做過爬蟲的都知道,要控制爬蟲的請(qǐng)求并發(fā)量,其實(shí)也就是控制其爬取頻率,以免被封IP,還有的就是以此來控制爬蟲應(yīng)用運(yùn)...
閱讀 1104·2021-09-22 15:37
閱讀 1131·2021-09-13 10:27
閱讀 2466·2021-08-25 09:38
閱讀 2445·2019-08-26 11:42
閱讀 1524·2019-08-26 11:39
閱讀 1554·2019-08-26 10:58
閱讀 2317·2019-08-26 10:56
閱讀 2569·2019-08-23 18:08