宅男在线永久免费观看网直播,亚洲欧洲日产国码无码久久99,野花社区在线观看视频,亚洲人交乣女bbw,一本一本久久a久久精品综合不卡

全部
常見問題
產(chǎn)品動(dòng)態(tài)
精選推薦

一直困擾 PHP 程序員的同步阻塞異步非阻塞,終于搞明白了

管理 管理 編輯 刪除

經(jīng)常聽到身邊寫 Java、Go 的朋友提到程序異步、非阻塞、線程、協(xié)程,讓系統(tǒng)性能提高到百萬、千萬并發(fā),使我甚是驚訝屬實(shí)羨慕。對于常年寫 PHP 的我來說,最初聽到這幾個(gè)詞時(shí),腦袋一直處于蒙圈狀態(tài),回過頭來看著自己手上同步阻塞的 PHP 代碼,心想著「異步、非阻塞、線程、協(xié)程」到底是個(gè)什么東東,這么厲害嘛。其實(shí) PHP 中也有線程、協(xié)程,但在日常的編程中幾乎不會(huì)使用,原因是 PHP-FPM 多進(jìn)程模式下并不支持線程、協(xié)程,使用 PHP 編程的程序員絕大多數(shù)都離不開 PHP-FPM 。這也就導(dǎo)致了 PHP 程序員對那些概念沒有接觸,那就更別提理解了,因此為了廣大的 PHP 程序員同胞們能夠和 Java、Go 的程序員對上話,特地對「同步、阻塞、異步、非阻塞」這幾個(gè)概念進(jìn)行了深度的分析,爭取把 PHP 程序員的腰桿挺直溜。

按照慣例先上八股文這道菜:

  • 同步阻塞:當(dāng)一個(gè)操作被調(diào)用時(shí),調(diào)用者將被阻塞,直到這個(gè)操作完成并返回結(jié)果。在此期間,調(diào)用者無法進(jìn)行其他任務(wù)。
  • 異步阻塞:當(dāng)一個(gè)操作被調(diào)用時(shí),調(diào)用者不會(huì)被阻塞,而是可以繼續(xù)執(zhí)行其他任務(wù)。然而,它仍然需要等待被調(diào)用的操作完成,并在操作完成后處理其結(jié)果。這個(gè)等待過程可能是阻塞的。
  • 同步非阻塞:調(diào)用者發(fā)起一個(gè)操作后,不會(huì)被阻塞并可以繼續(xù)執(zhí)行其他任務(wù)。雖然調(diào)用者可以立即獲得控制權(quán),但它仍然需要等待操作完成才能處理結(jié)果。在等待的過程中,調(diào)用者可以主動(dòng)輪詢或者不斷嘗試獲取操作結(jié)果,以避免長時(shí)間的阻塞。
  • 異步非阻塞:調(diào)用者發(fā)起一個(gè)操作后,不會(huì)被阻塞并可以繼續(xù)執(zhí)行其他任務(wù)。同時(shí),調(diào)用者也不需要等待操作完成來處理結(jié)果。相反,調(diào)用者可以注冊一個(gè)回調(diào)函數(shù)或者使用類似事件驅(qū)動(dòng)的機(jī)制,當(dāng)操作完成后被自動(dòng)觸發(fā)回調(diào)函數(shù)來處理結(jié)果。

基礎(chǔ)知識(shí)扎實(shí)的朋友看這個(gè)八股文就足以解惑了,不過看得懂八股文的畢竟是少數(shù)英俊帥氣人,你說氣不氣人集顏值與才華于一體,別看說的就是各位看官「哈哈」。言歸正傳,那看不懂八股文的怎么搞?別急,且聽我結(jié)合生活中的例子娓娓道來。

52960202501231142219653.png

你每天上班匆匆路過的早餐店,今天額外的多人,你湊近一看原來是來了位身材高挑楚楚動(dòng)人的美女服務(wù)員,結(jié)果你按耐不住心中的激動(dòng),今天高低得買兩個(gè)饅頭外加一杯豆?jié){,由于買的人太多,蒸好的饅頭早已賣完,這時(shí)你只能等正在蒸的,期間你什么也干不了只能眼勾勾的干等著,那么這時(shí)的你是同步阻塞的。

由于來買早餐的人越來越多,離上班的時(shí)間也越來越近,你開始了騷動(dòng),每隔幾分鐘就問美女服務(wù)員饅頭蒸好了沒?此時(shí)的你不再干等,而是開始刷刷抖音看看工作群,因?yàn)槟阋呀?jīng)付錢了所以還是得等饅頭,由于美女服務(wù)員太忙了沒空主動(dòng)告訴你,需要你自己不斷地問,那么這時(shí)的你是同步非阻塞的。

過了高峰期人變少了,視野更廣闊了,你看美女服務(wù)員更清楚了,結(jié)果你又開始眼勾勾的干等著,抖音也不刷了工作群的消息也不顧了。由于美女服務(wù)員不忙了,開始主動(dòng)叫那位身穿格子衫背雙肩包帥哥,饅頭蒸好了,這時(shí)的你甩了甩頭上的劉海,接過了美女服務(wù)員手中的饅頭會(huì)心一笑,順便還加了對方的微信,那么此時(shí)的你是異步阻塞的。

隔天你為了再睹芳容,又來到了這家早餐店,一向摳門的你甩手就點(diǎn)了兩個(gè)肉包。這時(shí)美女服務(wù)員迎面笑臉告知你肉包還需耐心等待哦,蒸好了會(huì)微信通知你。在炎炎的夏日里你路上走的太匆忙,此時(shí)的你口渴難耐,就去隔壁小賣部買了瓶82年的可樂,還坐著吹了會(huì)空調(diào)。隨著微信的一聲叮咚,你起身去早餐店,接過了美女服務(wù)員手中的肉包,那么此時(shí)的你是異步非阻塞的。

有了美女服務(wù)員的投喂,你工作的干勁都十足了,同時(shí)應(yīng)該也把「同步、阻塞、異步、非阻塞」這幾個(gè)概念搞懂了吧。其實(shí)這里的同步異步和阻塞非阻塞,容易搞混淆就像你看美女服務(wù)員容易丟魂一樣,在這個(gè)例子中同步異步需要關(guān)注的是「美女服務(wù)員是否會(huì)主動(dòng)的通知你」,主動(dòng)通知你那么對你來說就是異步的,需要你去詢問那么對你來說就是同步的。阻塞非阻塞需要關(guān)注的點(diǎn)是「你是否是眼勾勾的干等著」,如果你只能干等那就是阻塞的,如果你還能干點(diǎn)其他的事情比如刷抖音、買82年的可樂,那么就是非阻塞的。

美女也看了道理也懂了,有的朋友們又要產(chǎn)生新的疑問了,那在程序中怎么體現(xiàn)、怎么用「同步、阻塞、異步、非阻塞」呢?那我們就開始上代碼。

開整!

我們先來看同步阻塞的例子,使用 socket_create、socket_bind、socket_listen 函數(shù)創(chuàng)建綁定并監(jiān)聽了 8080 端口,然后一直阻塞在 socket_accept 函數(shù)上,直到有客戶端連接的到來。傳統(tǒng)的 PHP-FPM 就是同步阻塞的模式,不過 PHP-FPM 多進(jìn)程模型,在接收到客戶端連接 $client 后就交給由子進(jìn)程進(jìn)行后續(xù)的處理了,在這個(gè)例子只舉例了單進(jìn)程的模式。

<?php

// 同步阻塞模式

// 創(chuàng)建一個(gè)監(jiān)聽 Socket
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

// 綁定 8080 端口
socket_bind($socket, '0.0.0.0', 8080);

// 開始監(jiān)聽
socket_listen($socket);

while(true){
    // 會(huì)阻塞在這里,一直等著客戶端來連接
    // 結(jié)合剛剛的例子可以理解為,你一直在這里眼勾勾的干等饅頭,啥也干不了
    $client = socket_accept($socket);
    if($client){
        echo "客官來了" . PHP_EOL;
    }
}

再來看看同步非阻塞的例子,同樣也是監(jiān)聽了 8080 端口,不同的是將套接字 $socket 設(shè)置成了非阻塞模式。那么這種情況下將不會(huì)一直阻塞在 socket_accept 函數(shù)上,會(huì)繼續(xù)往下執(zhí)行,如果沒有寫其他的邏輯,就會(huì)出現(xiàn)放空炮的現(xiàn)象。這種模式在實(shí)際的編程中基本上不會(huì)采用,會(huì)把系統(tǒng)榨干,這一點(diǎn)值得注意一下,誰寫了這樣的代碼就要拉出去罰站了。

<?php

// 同步非阻塞模式

// 創(chuàng)建一個(gè)監(jiān)聽 Socket
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

// 綁定 8080 端口
socket_bind($socket, '0.0.0.0', 8080);

// 開始監(jiān)聽
socket_listen($socket);

// 這里設(shè)置成非阻塞
socket_set_nonblock($socket);

while(true){
    // 不會(huì)阻塞在這里
    $client = socket_accept($socket);
    if($client){
        echo "客官來了" . PHP_EOL;
    }

    // 會(huì)繼續(xù)往下執(zhí)行
    // 結(jié)合剛剛的例子,可以在這里刷刷抖音、看看工作群消息等
    // ...

    // 如果你上面沒有寫任何的邏輯,這些最好 sleep 一下
    // 不然 CPU 就會(huì)被榨干了,也就是說不要一直眼勾勾的盯著美女服務(wù)員會(huì)被吸干
    // 要適當(dāng)?shù)男菹⒁幌?    sleep(5);
}

繼續(xù)接著看看異步阻塞的例子,還好有 Swoole 不然這種模式的例子都沒有地方找了,這里感謝一下 Swoole 為 PHP 程序員做的貢獻(xiàn),讓我們硬氣了一回。構(gòu)造一個(gè) HTTP 服務(wù)并監(jiān)聽了 9501 端口,然后設(shè)置了針對 Request 的異步回調(diào)函數(shù),但如果在回調(diào)函數(shù)里面使用了類似 sleep、PDO 等的 PHP 原生函數(shù),就會(huì)阻塞整個(gè)進(jìn)程,導(dǎo)致無法處理其他的 Requset 請求。這種情況下的程序性能直接和同步阻塞等同了,所以異步阻塞模式在實(shí)際的編程實(shí)踐中也不常用,還不如使用同步阻塞模式了。這里提醒一點(diǎn),在新版的 Swoole 中已經(jīng)可以通過 HOOK 的方式支持 PHP 原生函數(shù)協(xié)程化了,這一點(diǎn)也值得慶幸。

<?php

// 異步阻塞模式

// 創(chuàng)建一個(gè) Swoole 的異步 HTTP 服務(wù)器
$http = new Swoole\Http\Server('127.0.0.1', 9501);

// 設(shè)置異步回調(diào)函數(shù)
$http->on('request', function ($request, $response) {
    // 阻塞了整個(gè)進(jìn)程,使用 PHP 原生的 PDO、Redis 等都會(huì)阻塞當(dāng)前進(jìn)程
    // 結(jié)合剛剛的例子,只能干等著,這里你啥也干不了
    sleep(5);

    $response->end("OK");
});

// 啟動(dòng)服務(wù)器
$http->start();

最后來看看異步非阻塞的例子,這種模式是目前在實(shí)踐中性能最好的,和上面例子唯一不同的是在 Request 回調(diào)函數(shù)中使用了協(xié)程類,便不會(huì)阻塞整個(gè)進(jìn)程,能夠釋放出 CPU 的控制權(quán)去處理其他的請求。當(dāng)然在新版的 Swoole 中也不一定需要使用協(xié)程類,使用原生的函數(shù)同樣不會(huì)阻塞進(jìn)程了,這一點(diǎn)大大減低了 PHP 程序員編程的心智負(fù)擔(dān)。

<?php

// 異步非阻塞模式

// 創(chuàng)建一個(gè) Swoole 的異步 HTTP 服務(wù)器
$http = new Swoole\Http\Server('127.0.0.1', 9501);

// 設(shè)置異步回調(diào)函數(shù)
$http->on('request', function ($request, $response) {
    // 不會(huì)阻塞整個(gè)進(jìn)程,這里還可以使用類似其他的協(xié)程客戶端
    // swoole\Coroutine\MySQL
    // swoole\Coroutine\Redis
    // 結(jié)合剛剛的例子,這里你可以去刷抖音、買82年的可樂
    // 也是說你有空去處理其他的請求了,不用這里干等
    // 等5秒過后,又可以回來繼續(xù)向下執(zhí)行,接過肉包之后你就可以上班去了,雖然你有百般不舍。
    Co::sleep(5);

    $response->end("OK");
});

// 啟動(dòng)服務(wù)器
$http->start();

看完這些,大家對「同步、阻塞、異步、非阻塞」的理解是不是又多了一些,了解這些概念對以后學(xué)習(xí) Go 語言也大有裨益。但是大家都知道這么一個(gè)道理,看懂了并不等于真的懂了,很多人一看就會(huì)一做就廢,因此最好自己上手實(shí)踐一下,在知中行,在行中知,做到知行合一。在市面上絕大多數(shù)的高性能程序都是異步非阻塞的模式,比如 Nginx、Redis 等,如果大家想寫出高性能的程序最好是優(yōu)先考慮這種模式,因?yàn)榻梃b才是最快的學(xué)習(xí)方法。本次分享的內(nèi)容到就此結(jié)束了,希望對大家能有所幫助。

注:本文轉(zhuǎn)載自“碼農(nóng)先森”,如有侵權(quán),請聯(lián)系刪除!

請登錄后查看

哈哈哈醬 最后編輯于2025-01-23 11:50:56

快捷回復(fù)
回復(fù)
回復(fù)
回復(fù)({{post_count}}) {{!is_user ? '我的回復(fù)' :'全部回復(fù)'}}
排序 默認(rèn)正序 回復(fù)倒序 點(diǎn)贊倒序

{{item.user_info.nickname ? item.user_info.nickname : item.user_name}} LV.{{ item.user_info.bbs_level || item.bbs_level }}

作者 管理員 企業(yè)

{{item.floor}}# 同步到gitee 已同步到gitee {{item.is_suggest == 1? '取消推薦': '推薦'}}
{{item.is_suggest == 1? '取消推薦': '推薦'}}
沙發(fā) 板凳 地板 {{item.floor}}#
{{item.user_info.title || '暫無簡介'}}
附件

{{itemf.name}}

{{item.created_at}}  {{item.ip_address}}
打賞
已打賞¥{{item.reward_price}}
{{item.like_count}}
{{item.showReply ? '取消回復(fù)' : '回復(fù)'}}
刪除
回復(fù)
回復(fù)

{{itemc.user_info.nickname}}

{{itemc.user_name}}

回復(fù) {{itemc.comment_user_info.nickname}}

附件

{{itemf.name}}

{{itemc.created_at}}
打賞
已打賞¥{{itemc.reward_price}}
{{itemc.like_count}}
{{itemc.showReply ? '取消回復(fù)' : '回復(fù)'}}
刪除
回復(fù)
回復(fù)
查看更多
打賞
已打賞¥{{reward_price}}
488
{{like_count}}
{{collect_count}}
添加回復(fù) ({{post_count}})

相關(guān)推薦

快速安全登錄

使用微信掃碼登錄
{{item.label}} 加精
{{item.label}} {{item.label}} 板塊推薦 常見問題 產(chǎn)品動(dòng)態(tài) 精選推薦 首頁頭條 首頁動(dòng)態(tài) 首頁推薦
取 消 確 定
回復(fù)
回復(fù)
問題:
問題自動(dòng)獲取的帖子內(nèi)容,不準(zhǔn)確時(shí)需要手動(dòng)修改. [獲取答案]
答案:
提交
bug 需求 取 消 確 定
打賞金額
當(dāng)前余額:¥{{rewardUserInfo.reward_price}}
{{item.price}}元
請輸入 0.1-{{reward_max_price}} 范圍內(nèi)的數(shù)值
打賞成功
¥{{price}}
完成 確認(rèn)打賞

微信登錄/注冊

切換手機(jī)號(hào)登錄

{{ bind_phone ? '綁定手機(jī)' : '手機(jī)登錄'}}

{{codeText}}
切換微信登錄/注冊
暫不綁定
CRMEB客服

CRMEB咨詢熱線 咨詢熱線

400-8888-794

微信掃碼咨詢

CRMEB開源商城下載 源碼下載 CRMEB幫助文檔 幫助文檔
返回頂部 返回頂部
CRMEB客服