一文詳解,PHP 協程:Go + Chan + Defer

2020-08-29 PHP編程愛好者

Swoole4.5為PHP語言提供了強大的CSP協程編程模式。底層提供了3個關鍵詞,可以方便地實現各類功能。

  • Swoole4.5提供的PHP協程語法借鑑自Golang,在此向GO開發組致敬
  • PHP+Swoole協程可以與Golang很好地互補。Golang:靜態語言,嚴謹強大性能好,PHP+Swoole:動態語言,靈活簡單易用

本文基於Swoole-4.2.9和PHP-7.2.9版本

關鍵詞

  • go :創建一個協程
  • chan :創建一個通道
  • defer :延遲任務,在協程退出時執行,先進後出

這3個功能底層實現全部為內存操作,沒有任何IO資源消耗。就像PHP的Array一樣是非常廉價的。如果有需要就可以直接使用。這與socket和file操作不同,後者需要向作業系統申請埠和文件描述符,讀寫可能會產生阻塞的IO等待。

協程並發

使用go函數可以讓一個函數並發地去執行。在編程過程中,如果某一段邏輯可以並發執行,就可以將它放置到go協程中執行。

順序執行

<?phpfunction test1() { sleep(1); echo &34;;}function test2() { sleep(2); echo &34;;}test1();test2();

執行結果:

htf@LAPTOP-0K15EFQI:~$ time php b1.phpbcreal 0m3.080suser 0m0.016ssys 0m0.063shtf@LAPTOP-0K15EFQI:~$

上述代碼中,test1和test2會順序執行,需要3秒才能執行完成。

並發執行

使用go創建協程,可以讓test1和test2兩個函數變成並發執行。

<?phpSwoole\Runtime::enableCoroutine();go(function () { sleep(1); echo &34;;});go(function () { sleep(2); echo &34;;});

Swoole\Runtime::enableCoroutine()作用是將PHP提供的stream、sleep、pdo、mysqli、redis等功能從同步阻塞切換為協程的異步IO

執行結果:

bchtf@LAPTOP-0K15EFQI:~$ time php co.phpbcreal 0m2.076suser 0m0.000ssys 0m0.078shtf@LAPTOP-0K15EFQI:~$

可以看到這裡只用了2秒就執行完成了。

  • 順序執行耗時等於所有任務執行耗時的總和 :t1+t2+t3...
  • 並發執行耗時等於所有任務執行耗時的最大值 :max(t1, t2, t3, ...)

協程通信

有了go關鍵詞之後,並發編程就簡單多了。與此同時又帶來了新問題,如果有2個協程並發執行,另外一個協程,需要依賴這兩個協程的執行結果,如果解決此問題呢?

答案就是使用通道(Channel),在Swoole4協程中使用new chan就可以創建一個通道。通道可以理解為自帶協程調度的隊列。它有兩個接口push和pop:

  • push:向通道中寫入內容,如果已滿,它會進入等待狀態,有空間時自動恢復
  • pop:從通道中讀取內容,如果為空,它會進入等待狀態,有數據時自動恢復

使用通道可以很方便地實現並發管理

<?php$chan = new chan(2); 協程2go(function () use ($chan) { $cli = new Swoole\Coroutine\Http\Client(&39;, 80); $cli->set([&39; => 10]); $cli->setHeaders([ &39; => &34;, &34; => &39;, &39; => &39;, &39; => &39;, ]); $ret = $cli->get(&39;); // $cli->body 響應內容過大,這裡用 Http 狀態碼作為測試 $chan->push([&39; => $cli->statusCode]);});39;www.163.com&39;timeout&39;Host&34;www.163.com&34;User-Agent&39;Chrome/49.0.2587.3&39;Accept&39;text/html,application/xhtml+xml,application/xml&39;Accept-Encoding&39;gzip&39;/&39;www.163.com&34;www.qq.com&34;www.163.com&34;a&34;~a&34;b&34;~b&34;c";});

執行結果:

htf@LAPTOP-0K15EFQI:~/swoole-src/examples/5.0$ time php defer.phpabc~b~areal 0m1.068suser 0m0.016ssys 0m0.047shtf@LAPTOP-0K15EFQI:~/swoole-src/examples/5.0$

結語

Swoole4提供的Go + Chan + Defer為PHP帶來了一種全新的CSP並發編程模式。靈活使用Swoole4提供的各項特性,可以解決工作中各類複雜功能的設計和開發。

在「疫情」期間已經淘汰了一批末端的業務coder,現在是自己努力成為資深程式設計師的好時機,才能在面對高薪職位邀請時,做到胸有成竹。為了大家能夠順利進階PHP中高級程式設計師、架構師,我為大家準備了一份中高級的教程福利!

作為web開發的佼佼者PHP並不遜色其他語言,加上swoole後更加是如虎添翼!進軍通信 、物聯網行業開發百度地圖、百度訂單中心等!年後更是霸佔程式設計師招聘語言第二名,寒冬裁員期過後正是各大企業擴大招人的時期,現在市場初級程式設計師泛濫,進階中高級程式設計師絕對是各大企業急需的人才,這套教程適合那些1-6年的PHP開發者進階中高級提升自己,在春招中找到高薪職位!

領取方式:點讚關注小編後私信【資料】獲取資料領取方式!

部分資料展示:

領取方式:點讚關注小編後私信【資料】獲取資料領取方式!

相關焦點

  • Golang協程並發的流水線模型
    go語言精簡優雅,既有編譯型語言的嚴謹和高性能,又有解釋型語言的開發效率,出色的並發性能也是go區別於其他語言的一大特色。go的並發編程代碼雖然簡單,但重在其並發模型和流程的設計。所以這裡總結下golang協程並發常用的流水線模型。
  • Go語言中的常見的幾個坑
    什麼是協程洩漏,大體的意思是主程序已經跑完了,但是主程序中開的go協程沒有結束。如何知道協程是否發生了洩漏,最簡單的方法是runtime.NumGoroutine()得到結果是否與你的期望值一樣,如果大了就是發生了洩漏。哪些問題會導致協程洩漏?
  • go 學習筆記之解讀什麼是defer延遲函數
    中文翻譯文檔"defer"語句調用一個函數,該函數的執行被推遲到周圍函數返回的那一刻,這是因為周圍函數執行了一個return語句,到達了函數體的末尾,或者是因為相應的協程正在驚慌.當前協程正驚慌失措because the corresponding goroutine is panicking周圍函數萬一發生 panic 時也會先運行前面已經定義好的 defer 語句,而 panic 後續代碼因為沒有特殊處理,所以程序崩潰了也就無法運行.
  • golang chan 探究
    當時就覺得這玩意很神奇, 因為之前接觸過的不管是php, java, 很明顯, 管道是go實現在語言層面的功能, 所以我以為需要去翻他的源碼了.go tool compile -N -l -S main.go雖然彙編咱看不懂, 但是其中有一行還是引起了我的注意.
  • 使用 go 協程+Channel,讓你的代碼執行快到起飛
    sync.WaitGroup{}, uidTargetChan: make(chan int, 100), } // 利用協程啟動獲取targetUid的服務 go func() { getTargetUid(uh, uth) }() // 記錄下這些targetUid,uidTargetList就是最後保存所有符合條件的uid var uidTargetList []int go func(
  • PHP協程:並發 shell_exec
    在Swoole4協程環境下可以用Co::exec並發地執行很多命令。本文基於Swoole-4.2.9和PHP-7.2.9版本協程示例<?php$c = 10;while($c--) { go(function () { //這裡使用 sleep 5 來模擬一個很長的命令 co::exec(&34;); });}返回值Co::exec執行完成後會恢復掛起的協程,並返回命令的輸出和退出的狀態碼。
  • client-go和golang源碼中的技巧
    { go func(i int) { defer wg.Done() fmt.Print(i, &34;) }(i) } wg.Wait()}結果:9 4 0 1 2 3 6 5 7 8 協程間使用chan進行同步下例中使用
  • 讓Go無路可go的十個方法
    { resp, err := http.Get(&34;) defer resp.Body.Close() if err !{ ch := make(chan string, 1) ch <- &34; close(ch) ch <- &34;}運行結果:panic: send on closed channelgoroutine 1 [running]:main.main() /Users/eddycjy/go-application
  • GO語言:協程——Goroutine
    協程協程是一種用戶態的輕量級線程,又稱微線程,英文名Coroutine,協程的調度完全由用戶控制。人們通常將協程和子程序(函數)比較著理解。 子程序調用總是一個入口,一次返回,一旦退出即完成了子程序的執行。
  • Swoole協程與Go協程的區別,很詳細,很牛逼
    進程、線程、協程的概念進程是什麼?進程就是應用程式的啟動實例。例如:打開一個軟體,就是開啟了一個進程。進程擁有代碼和打開的文件資源,數據資源,獨立的內存空間。線程是什麼?線程屬於進程,是程序的執行者。一個進程至少包含一個主線程,也可以有更多的子線程。線程有兩種調度策略,一是:分時調度,二是:搶佔式調度。協程是什麼?
  • 面試官:實現協程同步有哪些方式?
    假設現在有多個協程並發訪問操作同一塊內存中的數據,那麼可能上一納秒第一個協程剛把數據從寄存器拷貝到內存,第二個協程馬上又把此數據用它修改的值給覆蓋了,這樣共享數據變量會亂套。gt; go run test.go1014184dashu@dashu > /data1/htdocs/go_practice > go run test.go1026029dashu@dashu > /data1/htdocs/go_practice > go run test.go19630...
  • PHP協程聽說過嗎?
    以前一直用這個php開發語言,作web開發真的是太方便了。第一它的數據類型可以自動轉換的弱類型的語言。莫名的某一天被大神問到PHP協程有什麼缺點,我彪呼呼的說不聽過。後來自己進資料惡補總結如下[分享給那些和我當時一樣的你]:首先說啥是進程、線程、協程:進程是系統調度最小單位,線程是在進程中共享進程的資料,我就簡單這些概括了,因為這個不是重點。協程是啥,線程在系統內核態叫線程,在用戶太就叫協程。這樣理解協助管理線程。
  • 2020-10-28:go中,好幾個go程,其中一個g...
    2.有panic的子協程裡的defer能執行,主協程和其他子協程裡的defer不執行或者只能執行一半,這打破了【defer函數一定執行】的規則。go代碼如下:package mainimport ( "fmt" "time")func main() { defer func() { recover() }() defer func() { fmt.Println("defer main")
  • Mix PHP V2.2 發布,與 go-micro 深度集成的 PHP 微服務開發框架
    本次版本更新主要是增加微服務開發相關的組件與開發骨架,從上一次 Mix V2.1 非常激進的切換為單線程協程後 [為何從 Reactor+Manager+Worker 多進程改為單線程協程],Mix V2.2 在微服務方面也非常激進的選擇了和其他 Swoole 框架截然不同的路徑:與 go-micro 微服務生態深度集成,借用 golang 微服務生態的治理工具
  • Mix PHP V2.2 發布,與 go-micro 深度集成的 PHP 微服務開發框架...
    ,Mix 從 V2.1 開始完全切換為單線程協程,這一特性非常適合微服務的打造,同時 Mix 一直都是 Go 風格框架,因此我決定將微服務融入 go-micro 生態,讓 Mix 框架用戶能與 go-micro 編寫的微服務直接代碼級無縫通信,並且能直接使用 go-micro 運行時工具包的網關、代理、Dashboard 等全部微服務治理基礎設施,讓 PHP 與 Go 能一起開發高性能微服務,取長補短
  • 手把手教你用Go語言打造一款簡易TCP埠掃描器
    func(i int) {             //釋放wg             defer wg.Done()             var address = fmt.Sprintf("%s:%d", ip, i)             //conn, err := net.DialTimeout("tcp", address, time.Second*10)
  • php和go寫入MySQL速度誰更快?
    php和go插入mysql數據速度的比較pk1.插入1w條記錄結果比較phpphpgogo結果:php和go基本都是11s左右,速度 基本相當。插入10w條記錄phpphp10go>go10結果可以看出來,php不到2分鐘,而go需要2分鐘以上,php更快一點。