欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

如何用PHP實現(xiàn)多線程編程

 更新時間:2021年05月26日 10:09:08   作者:枕邊書  
原以為 PHP 普遍都是單線程模型,并不適合多線程領域,發(fā)現(xiàn)PHP的多線程也頗有可取之處,用來解決某些問題竟然非常適合。本文對比多進程介紹了下多線程的優(yōu)勢和適用場景,提出了一種巧用方案,并使用PHP代碼實現(xiàn)了多線程的常見用法。

多線程

線程

首先說下線程:

線程(thread) 是操作系統(tǒng)能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。一條線程指的是進程中一個單一順序的控制流,一個進程中可以并發(fā)多個線程,每條線程并行執(zhí)行不同的任務.

使用多線程主要是因為它在執(zhí)行效率上有很大優(yōu)勢。由于線程是操作系統(tǒng)能夠進行調度的最小單位:

  • 一個多線程程序比單線程程序被操作系統(tǒng)調度的概率更大,所以多線程程序一般會比單線程程序更高效;
  • 多線程程序的多個線程可以在多核 CPU 的多個核心同時運行,可以將完全發(fā)揮機器多核的優(yōu)勢;

同時對比多進程程序,多線程有以下特點:

  • 線程的創(chuàng)建和切換的系統(tǒng)開銷都比進程要小,所以一定程度上會比多進程更高效;
  • 線程天生的共享內(nèi)存空間,線程間的通信更簡單,避免了進程IPC引入新的復雜度。

適用場景

多線程的優(yōu)化是很多,可是無腦使用多線程并不能提升程序的執(zhí)行效率,因為線程的創(chuàng)建和銷毀、上下文切換、線程同步等也是有性能損耗的,耗費時間可能比順序執(zhí)行的代碼還多。如:

sumSmall是一個從1累加到50000的函數(shù)。

上圖是在主線程內(nèi)執(zhí)行了三次 sumSmall 和三個線程分別執(zhí)行 sumSmall ,再將結果同步到一個線程的時間對比,我們會發(fā)現(xiàn)只在主線程執(zhí)行的時間反而更短,三個線程創(chuàng)建、切換、同步的時間遠遠大過了線程異步執(zhí)行節(jié)省的時間。

而函數(shù) sumLarge 從1累加到5000000,下圖同一線程執(zhí)行三次和三個線程執(zhí)行的耗時:

這次,多線程終于有效率優(yōu)勢了。

是否使用多線程還需要根據(jù)具體需求而定,一般考慮以下兩種情況:

  • I/O 阻塞會使操作系統(tǒng)發(fā)生任務調度,阻塞當前任務,所以代碼中 I/O 多的情況下,使用多線程時可以將代碼并行。例如多次讀整塊的文件,或請求多個網(wǎng)絡資源。
  • 多線程能充分利用 CPU,所以有多處大計算量代碼時,也可以使用多線程使他們并行執(zhí)行,例如上文中后一個例子。

PHP中的多線程

PHP 默認并不支持多線程,要使用多線程需要安裝 pthread 擴展,而要安裝 pthread 擴展,必須使用 --enable-maintainer-zts 參數(shù)重新編譯 PHP,這個參數(shù)是指定編譯 PHP 時使用線程安全方式。

線程安全

多線程是讓程序變得不安分的一個因素,在使用多線程之前,首先要考慮線程安全問題:

線程安全:線程安全是編程中的術語,指某個函數(shù)、函數(shù)庫在多線程環(huán)境中被調用時,能夠正確地處理多個線程之間的共享變量,使程序功能正確完成。

在傳統(tǒng)多線程中,由于多個線程共享變量,所以可能會導致出現(xiàn)如下問題:

1.存在一個全局數(shù)組$arr = array('a');;

2.A 線程獲取數(shù)組長度為1;

3.B 線程獲取數(shù)組長度為1;

4.A 線程 pop 出數(shù)組元素 $a = array_pop($arr); $a = 'a';;

5.B 線程也 pop 數(shù)組元素 $b = array_pop($arr); $a = null;;

6.此時 B 線程內(nèi)就出現(xiàn)了靈異事件,明明數(shù)組長度大于0,或沒有 pop 出東西;

PHP 實現(xiàn)

PHP 實現(xiàn)的線程安全主要是使用 TSRM 機制對 全局變量和靜態(tài)變量進行了隔離,將全局變量和靜態(tài)變量 給每個線程都復制了一份,各線程使用的都是主線程的一個備份,從而避免了變量沖突,也就不會出現(xiàn)線程安全問題。

PHP 對多線程的封裝保證了線程安全,程序員不用考慮對全局變量加各種鎖來避免讀寫沖突了,同時也減少了出錯的機會,寫出的代碼更加安全。

但由此導致的是,子線程一旦開始運行,主線程便無法再對子線程運行細節(jié)進行調整了,線程一定程度上失去了線程之間通過全局變量進行消息傳遞的能力。

同時 PHP 開啟線程安全選項后,使用 TSRM 機制分配和使用變量時也會有額外的損耗,所以在不需要多線程的 PHP 環(huán)境中,使用 PHP 的 ZTS (非線程安全) 版本就好。

類和方法

PHP 將線程 封裝成了 Thread 類,線程的創(chuàng)建通過實例化一個線程對象來實現(xiàn),由于類的封裝性,變量的使用只能通過構造函數(shù)傳入,而線程運算結果也需要通過類變量傳出。

下面介紹幾個常用的 Thread 類方法:

  • run():此方法是一個抽象方法,每個線程都要實現(xiàn)此方法,線程開始運行后,此方法中的代碼會自動執(zhí)行;
  • start():在主線程內(nèi)調用此方法以開始運行一個線程;
  • join():各個線程相對于主線程都是異步執(zhí)行,調用此方法會等待線程執(zhí)行結束;
  • kill():強制線程結束;
  • isRunning():返回線程的運行狀態(tài),線程正在執(zhí)行run()方法的代碼時會返回 true;

因為線程安全的實現(xiàn),PHP 的多線程開始運行后,無法再通過共享內(nèi)存空間通信,線程也無法通過線程間通信復用,所以我認為 PHP 的“線程池”并沒有什么意義。擴展內(nèi)自帶的Pool 類是一個對多線程分配管理的類,這里也不再多介紹了。

實例代碼

下面是一個線程類,用來請求某一接口。接下來根據(jù)它寫兩個多線程的應用實例:

class Request extends Thread {
    public $url;
    public $response;
    public function __construct($url) {
        $this->url = $url;
    }
    public function run() {
        $this->response = file_get_contents($this->url);
    }
}

異步請求

將同步的請求拆分為多個線程異步調用,以提升程序的運行效率。

$chG = new Request("www.google.com");
$chB = new Request("www.baidu.com");
$chG ->start();
$chB ->start();
$chG->join();
$chB->join();

$gl = $chG->response;
$bd = $chB->response;

超時控制

偶然間發(fā)現(xiàn)公司網(wǎng)站某一網(wǎng)頁上的一塊內(nèi)容時有時無,不知道具體實現(xiàn),但這給了我使用多線程的靈感:利用線程異步實現(xiàn)快速失敗和超時控制。

我們在使用 curl 請求某個地址時,可以通過 CURLOPT_CONNECTTIMEOUT / CURLOPT_TIMEOUT 參數(shù)分別設置 curl 的連接超時時間和讀取數(shù)據(jù)超時時間,但總的超時時間不好控制。而且在進行數(shù)據(jù)庫查詢時的超時時間無法設置(鳥哥博客:為MySQL設置查詢超時)。

這時我們便可以借用多線程來實現(xiàn)此功能:在執(zhí)行線程類的 start() 方法后,不調用 join() 方法,使線程一直處于異步狀態(tài),不阻塞主線程的執(zhí)行。

此時主線程相當于旗艦,而各子線程相當于巡航艦,旗艦到達某地后不必要一直等待巡航艦也歸來,等待一段時間后離開即可,從而避免巡航艦意外時旗艦白白空等。

代碼:

$chG = new Request("www.google.com");
$chB = new Request("www.baidu.com");
$chG->start();
$chB->start();
$chB->join();
// 此處不對chG執(zhí)行join方法

sleep(1); // sleep一個能接受的超時時間
$gl = $chG->response;
$bd = $chB->response;
$bd->kill();
if (!$gl) {
    $gl = ""; // 處理異常,或在線程類內(nèi)給$gl一個默認值
}

總結

PHP 對多線程進行的封(yan)裝(ge),讓人用線程用得非常不盡興。雖然安全,也保持 PHP 簡單易用的一貫風格,卻無法完全發(fā)揮多線程的能力。

以上就是如何用PHP實現(xiàn)多線程編程的詳細內(nèi)容,更多關于用PHP實現(xiàn)多線程編程的資料請關注腳本之家其它相關文章!

相關文章

  • PHP反射原理與用法深入分析

    PHP反射原理與用法深入分析

    這篇文章主要介紹了PHP反射原理與用法,結合實例形式深入分析了PHP反射的概念、原理、應用場景及相關操作技巧,需要的朋友可以參考下
    2019-09-09
  • php面向對象的方法重載兩種版本比較

    php面向對象的方法重載兩種版本比較

    “重載”是類的多態(tài)的一種實現(xiàn)。函數(shù)重載指一個標識符被用作多個函數(shù)名,且能夠通過函數(shù)的參數(shù)個數(shù)或參數(shù)類型將這些同名的函數(shù)區(qū)分開來,調用不發(fā)生混淆。這樣做的主要好處就是,不用為了對不同的參數(shù)類型或參數(shù)個數(shù),而寫多個函數(shù)。
    2008-09-09
  • PHP文件緩存內(nèi)容保存格式實例分析

    PHP文件緩存內(nèi)容保存格式實例分析

    這篇文章主要介紹了PHP文件緩存內(nèi)容保存格式,是PHP程序開發(fā)中非常實用的功能,需要的朋友可以參考下
    2014-08-08
  • 淺析HTTP消息頭網(wǎng)頁緩存控制以及header常用指令介紹

    淺析HTTP消息頭網(wǎng)頁緩存控制以及header常用指令介紹

    本篇文章是對HTTP消息頭網(wǎng)頁緩存控制以及header常用指令進行了詳細的分析介紹,需要的朋友參考下
    2013-06-06
  • PHP 字符串分割和比較

    PHP 字符串分割和比較

    比較兩個字符串是否相等,最常見的方法就是使用“===”來判斷,至于它和“==”的區(qū)別,簡單來說就是前者強調“Identical”類型也要求一樣;后者要求“Equal”,值相同就可以了。
    2009-10-10
  • 深入理解PHP之OpCode原理詳解

    深入理解PHP之OpCode原理詳解

    這篇文章主要介紹了深入理解PHP之OpCode原理,較為詳細的分析了php程序的相關編譯機制與運行原理,需要的朋友可以參考下
    2016-06-06
  • PHP獲取數(shù)組中某元素的位置及array_keys函數(shù)應用

    PHP獲取數(shù)組中某元素的位置及array_keys函數(shù)應用

    獲取數(shù)組中一元素的位置有很多方法,其中PHP自身就已經(jīng)內(nèi)置了一個函數(shù)array_keys(),下邊的代碼能夠打印出所有PHP的內(nèi)置函數(shù),感興趣的朋友可以了解下同時學習一下函數(shù)array_keys()的使用方法,就當鞏固知識量啦
    2013-01-01
  • PHP中冒號、endif、endwhile、endfor使用介紹

    PHP中冒號、endif、endwhile、endfor使用介紹

    下面的一些用法,對于相當一部分PHP愛好者來說根本沒見過啊,這些是什么東西呢?
    2010-04-04
  • PHP 抽象方法與抽象類abstract關鍵字介紹及應用

    PHP 抽象方法與抽象類abstract關鍵字介紹及應用

    抽象方法指沒有方法體的方法,只要一個類里面有一個方法是抽象方法,那么這個類就要定義為抽象類,不了解的朋友可以看看
    2014-10-10
  • 使用ThinkPHP8實現(xiàn)導出Excel數(shù)據(jù)表格功能

    使用ThinkPHP8實現(xiàn)導出Excel數(shù)據(jù)表格功能

    這篇文章主要為大家詳細介紹了如何使用ThinkPHP8導出Excel數(shù)據(jù)表格功能,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2024-05-05

最新評論