# 協程
Swoole在2.0開始內置協程(Coroutine)的能力,提供了具備協程能力IO接口(統一在命名空間Swoole\Coroutine\*)
>2.0.2或更高版本已支持PHP7
協程可以理解為純用戶態的線程,其通過協作而不是搶占來進行切換。相對于進程或者線程,協程所有的操作都可以在用戶態完成,創建和切換的消耗更低。Swoole可以為每一個請求創建對應的協程,根據IO的狀態來合理的調度協程,這會帶來了以下優勢:
* 開發者可以無感知的用同步的代碼編寫方式達到異步IO的效果和性能,避免了傳統異步回調所帶來的離散的代碼邏輯和陷入多層回調中導致代碼無法維護。
* 同時由于swoole是在底層封裝了協程,所以對比傳統的php層協程框架,開發者不需要使用yield關鍵詞來標識一個協程IO操作,所以不再需要對yield的語義進行深入理解以及對每一級的調用都修改為yield,這極大的提高了開發效率。
**啟用協程**
* PHP版本要求:>= 5.5,包括5.5、5.6、7.0、7.1
* 基于swoole_server或者swoole_http_server進行開發,目前只支持在onRequet, onReceive, onConnect事件回調函數中使用協程。
swoole提供了四種協程Client:
* TCP/UDP Client->\Swoole\Coroutine\Client
* HTTP Client->\Swoole\Coroutine\HTTP\Client
* Redis Client->\Swoole\Coroutine\Redis
* Mysql Client->\Swoole\Coroutine\MySQL
可以滿足大部分開發者的需求。對于私有協議,開發者可以使用協程的TCP或者UDP接口去方便的封裝。
在協程Server中需要使用協程版Client,可以實現全異步server
同時swoole提供了協程工具集:\Swoole\Coroutine\Util,提供了獲取當前協程id,反射調用等能力。
```php
<?php
$client = new Swoole\Coroutine\Client(SWOOLE_SOCK_TCP);
$client->connect("127.0.0.1", 8888, 0.5);
//調用connect將觸發協程切換
$client->send("hello world from swoole");
//調用recv將觸發協程切換
$ret = $client->recv();
$client->close();
echo $ret;
```
當代碼執行到connect()和recv()函數時,swoole會觸發進行協程切換,此時swoole可以去處理其他的事件或者接受新的請求。當此client連接成功或者后端服務回包后,swoole server會恢復協程上下文,代碼邏輯繼續從切換點開始恢復執行。開發者整個過程不需要關心整個切換過程。具體使用可以參考client的文檔。
支持協程的回調方法列表
目前Swoole2 僅有部分事件回調函數底層自動創建了協程,可以調用協程客戶端。本節列出了支持協程客戶端的回調列表以及實現的版本號。
v2.0.5
* onConnect
* onReceive
* onPacket
* onRequest
* onHandShake
v2.0.6
* onMessage
v2.0.7
* onOpen
* Redis\Server->handler
v2.0.9
* tick/after 定時器
v2.0.10
* onPipeMessage
**新增配置**
在Swoole\Server的set方法中增加了一個配置參數max_coro_num,用于配置一個worker進程最多同時處理的協程數目。因為隨著worker進程處理的協程數目的增加,其占用的內存也會增加,為了避免超出php的memory_limit限制,請根據實際業務的壓測結果設置該值,默認為3000。
**注意事項**
* 全局變量:協程使得原有的異步邏輯同步化,但是在協程的切換是隱式發生的,所以在協程切換的前后不能保證全局變量以及static變量的一致性。
* 請勿在以下場景中觸發協程切換:
* 析構函數
* 魔術方法__call()
* gcc 4.4下如果在編譯swoole的時候(即make階段),出現```gcc warning: dereferencing pointer ‘v.327’ does break strict-aliasing rules、 dereferencing type-punned pointer will break strict-aliasing rules``` 請手動編輯Makefile,將CFLAGS = -Wall -pthread -g -O2替換為CFLAGS = -Wall -pthread -g -O2 -fno-strict-aliasing,然后重新編譯make clean;make;make install
* **`與xdebug、xhprof等zend擴展不兼容`**,例如不能使用xhprof對協程server進行性能分析采樣。
* 原生的call_user_func和call_user_func_array中無法使用協程client,請使用\Swoole\Coroutine::call_user_func和\Swoole\Coroutine::call_user_func_array代替,在PHP7中如果無法保證在編譯時反射調用的類是編譯器已知的,請統一使用協程版反射調用
- swoole簡介
- swoole功能概述
- 序章
- 開發必讀
- 1 環境搭建
- 1.1 環境搭建
- 1.2 搭建Echo服務器
- 2 初識Swoole
- 2.1 Worker進程
- 2.2 TaskWorker進程
- 2.3 Timer定時器
- 2.4 Process進程
- 2.5 Table內存表
- 2.6 多端口監聽
- 2.7 sendfile文件支持
- 2.8 SSL支持
- 2.9 熱重啟
- 2.10 http_server
- 附錄*server配置
- 附錄*server函數
- 附錄*server屬性
- 附錄*server回調函數
- 附錄*server高級特性
- 心跳檢測
- 3 Swoole協議
- 3.1 EOF協議
- 3.2 固定包頭協議
- 3.3 Http協議
- 3.4 WebSocket協議
- 3.5 MTQQ協議
- 內置http_server
- 內置websocket_server
- Swoole\Redis\Server
- 4 Swoole異步IO
- 4.1 AsyncIO
- 異步文件系統IO
- swoole_async_readfile
- swoole_async_writefile
- swoole_async_read
- swoole_async_write
- 5 swoole異步客戶端
- ws_client
- http_client
- mysql_client
- redis_client
- tcp_client
- http2_client
- 6 swoole協程
- Swoole\Coroutine\Http\Client
- Swoole\Coroutine\MySQL
- Swoole\Coroutine\Redis
- Coroutine\PostgreSQL
- Swoole\Coroutine\Client
- Swoole\Coroutine\Socket
- Swoole\Coroutine\Channel
- Coroutine
- Swoole\Coroutine::create
- Swoole\Coroutine::resume
- Swoole\Coroutine::suspend
- Swoole\Coroutine::sleep
- Coroutine::getaddrinfo
- Coroutine::gethostbyname
- swoole_async_dns_lookup_coro
- Swoole\Coroutine::getuid
- getDefer
- setDefer
- recv
- Coroutine::stats
- Coroutine::fread
- Coroutine::fget
- Coroutine::fwrite
- Coroutine::readFIle
- Coroutine::writeFIle
- Coroutine::exec
- 7 swoole_process
- process::construct
- process::start
- process::name
- process::signal
- process::setaffinity
- process::exit
- process::kill
- process::daemon
- process->exec
- process::wait
- process::alarm
- 8 swoole定時器
- swoole_timer_tick
- swoole_timer_after
- swoole_timer_clear
- 9 swoole_event
- swoole_event_add
- swoole_event_set
- swoole_event_del
- swoole_event_wait
- swoole_event_defer
- swoole_event_write
- swoole_event_exit
- swoole提供的function
- 常見問題
- 客戶端鏈接失敗原因
- 如何設置進程數
- 如何實現異步任務
- 如何選擇swoole三種模式
- php中哪些函數是阻塞的
- 是否可以共用1個redis或mysql連接
- 如何在回調函數中訪問外部的變量
- 為什么不要send完后立即close
- 不同的Server程序實例間如何通信
- MySQL的連接池、異步、斷線重連
- 在php-fpm或apache中使用swoole
- 學習Swoole需要掌握哪些基礎知識
- 在phpinfo中有在php-m中沒有
- 同步阻塞與異步非阻塞選擇
- CURL發送POST請求服務器端超時
- 附錄
- 預定義常量
- 內核參數調優
- php四種回調寫法
- 守護進程程序常用數據結構
- swoole生命周期
- swoole_server中內存管理機制
- 使用jemalloc優化swoole內存分配性能
- Reactor、Worker、Task的關系
- Manager進程
- Swoole的實現
- Reactor線程
- 安裝擴展
- swoole-worker手冊
- swoole相關開源項目
- 寫在后面的話
- 版本更新記錄
- 4.0