PHP는 코 루틴 비동기 비 차단 IO 개발과 swoole

"코 루틴이 이니셔티브에 자원을 전송 방해의 얼굴에 중단 될 수 있으며, 스케줄러는. 다른 코 루틴 실행을 선택하기 위해 IO를 비 차단 달성하기 위해"
장애물의 얼굴이 더 의미, 또는 코드의 동기 실행하지 실행 비동기 프로세스를 넘겨하지 않을 경우 다음과 같이하지만 PHP는, 네이티브 코 루틴을 지원하지 않습니다
함수 foo ()
{
    $ DB를 = 새로운 DB ();
    $ 결과 = (수율 $의 DB-> 쿼리 ());
    $ 결과를 얻을;
}
위의 데이터베이스 쿼리 작업이 차단,이 단계는 스케줄러가 코 루틴을 예약 할 때 차단 작업을 수행 할 수 발견, 다음 스케줄러는 어떻게 할까? 나머지 코 루틴 실행을 선택? 를 시행 넘겨 차단의 과정을 수행한다 협력, 그? 그래서 비 차단 IO는 PHP 협회 과정에서 집단 괴롭힘에 대해 이야기 비동기 호출에 속하는 치워.
swoole 비동기 작업은 swoole_task에 공식 문서를 참조 할 수 있습니다, 비동기 구현하는 솔루션을 제공합니다
핵심 기능 및
 
제 요청 코 루틴을 형성
 
먼저 swoole_server 및 세트 콜백을 만들
클래스 HttpServer에 서버를 구현
{
    개인 $ swooleHttpServer;
 
    공공 기능 __construct (\ swoole_http_server $ swooleHttpServer)
    {
        $ this-> swooleHttpServer = $ swooleHttpServer;
    }
 
    공공 기능의 시작 ()
    {
        $ this-> swooleHttpServer->에 ( '시작'[$이 'ONSTART']);
        $ this-> swooleHttpServer->에 ( '종료'[$이 'onShutdown']);
 
        $ this-> swooleHttpServer->에 ( 'workerStart'[$이 'onWorkerStart']);
        $ this-> swooleHttpServer->에 ( 'workerStop'[$이 'onWorkerStop']);
        $ this-> swooleHttpServer->에 ( 'workerError'[$이 'onWorkerError']);
        $ this-> swooleHttpServer->에 ( '업무'[$이 'onTask']);
        $ this-> swooleHttpServer->에 ( '마무리'[$이 'onFinish']);
 
 
        $ this-> swooleHttpServer->에 ( "요구", [$이 'onRequest를']);
 
        $ this-> swooleHttpServer- 시작> ();
    }
onRequest 방법 :
 공공 기능 onRequest (\ swoole_http_request의 $ 요청, \ swoole_http_response의 $ 응답)
    {
        = 새로운 RequestHandler를 RequestHandler를 $ ($ 요청 $ 반응);
        $ requestHandler-> 핸들 ();
    }
방법으로는, 라우팅 요청을 파싱하기 ReqeustHandler에게 핸들을 수행하고, 제어부 적절한 메소드를 호출 만들어
 공공 기능 핸들 ()
    {
        $ this-> 컨텍스트 = 새로운 컨텍스트 ($ this-> 요청 $ this-> 반응 $ this-> getFd ());
        $ this-> = 새로운 라우터 라우터 ($ this-> 요청);
 
        {시도
            경우 (거짓 === $ this-> 라우터 기반> 구문 분석 ()) {
                $ this-> 응답 -> 출력 ( '');
                반환;
            }
            $ 코 루틴 = $ this-> doRun ();
            $ 작업 = 새 작업 ($ 코 루틴, $ this-> 컨텍스트);
            $ task-> 실행 ();
        } 캐치 (\ 예외 $ 전자) {
            PcsExceptionHandler :: 핸들 ($ 전자, $ this-> 응답);
        }
    }
    
 전용 기능 doRun ()
    {
        $ RET = ($ this- 수율> 디스패치 ());
        수율 $ this-> 응답 -> ($의 RET) 보내;
    }
위의 코드는 (), $ this-를 얻을 수있다> 응답 ->를 ($의 RET)을 보내 RET 액션을 호출 한 결과이며, 클라이언트 요청에 대한 응답이다.
이번에는 코 루틴 (Genetator 객체) 요청의 전체 흐름을 포함하고, 형성된 코 루틴 $ 요청되면, 다음 단계는 실제 얻었다 스케줄링 코 루틴의 실행 결과를 수행하는 것이다.
 
예약 코 루틴
 
네임 스페이스 PC를 \ 코 루틴;
 
사용하는 PC를 \ 네트워크 \ 문맥 \ 컨텍스트;
 
클래스 작업
{
    개인 $의 코 루틴;
    개인 $ 컨텍스트;
    개인 $ 상태;
    개인 $ 스케줄러;
    개인 $ sendValue;
 
    공공 기능 __construct (\ 발전기 $의 코 루틴, 컨텍스트 $ 컨텍스트)
    {
        $ this-> 코 루틴 = $ 코 루틴;
        $ this-> 컨텍스트 = $ 컨텍스트;
        $ this-> 스케줄러 = 새로운 스케줄러 ($이);
 
    }
 
    공공 기능 실행 ()
    {
        동안 (사실) {
            {시도
                $ this-> 상태 = $ this-> scheduler-> 일정 ();
                스위치 ($ this-> 상태) {
                    경우 TaskStatus :: TASK_WAIT :
                        에코 "작업 상태 : TASK_WAIT \ n을";
                        NULL을 반환;
 
                    경우 TaskStatus :: TASK_DONE :
                        "TASK_DONE \ 없음 작업 상태를"; 에코
                        NULL을 반환;
 
                    경우 TaskStatus :: TASK_CONTINUE;
                        "TASK_CONTINUE \ 없음 작업 상태를"; 에코
                        단절;
                }
 
            } 캐치 (\ 예외 $ 전자) {
                $ this-> scheduler-> throwException ($ E);
            }
        }
    }
    공공 기능 setCoroutine ($의 코 루틴)
    {
        $ this-> 코 루틴 = $ 코 루틴;
    }
 
    공개 getCoroutine 함수 ()
    {
        $ this-> 코 루틴을 반환;
    }
 
    공개 유효한 함수 ()
    {
        경우 ($ this-> coroutine-> 유효한 ()) {
            true를 반환;
        } 다른 {
            false를 반환;
        }
    }
 
    공공 기능 전송 ($ 값)
    {
        $ this-> sendValue = $ 값;
        $ RET = $ this-> coroutine-> ($ 값)를 전송;
        $ 권리를 반환;
    }
 
    공개 getSendVal 함수 ()
    {
        > sendValue을 $ this-를 반환;
    }
}
작업 생성기 객체는, 코 루틴의 $에 따라 약간의 get / set 메소드를 정의하고, 어떤 방법으로 발전기 작업 클래스는 작업 :: run () 메소드는 각각 일정 스케줄링 동작에 의해 실행되는 코 루틴의 스케줄링을 수행하는 데 사용됩니다 시간표는 일정의 현재 상태로 돌아갑니다. 공동 루틴 복수의 스케줄러를 공유하고, 각 코 루틴은 클라이언트의 요청 때문에 실행 방법은 여기에 상호 영향을 줄이기 위해 별도의 스케줄러를 사용하여, 각각에 대해 코 루틴 스케줄러를 생성하고, 공동 복수의 루틴 사이에 일정 순서는 여기 걱정없이 swoole, 스케줄러를 처리합니다. 예약 된 코드는 아래와 같습니다 :
네임 스페이스 PC를 \ 코 루틴;
 
클래스 스케줄러
{
    개인 $ 작업;
    개인 $ 스택;
    CONST SCHEDULE_CONTINUE = 10;
 
    공공 기능 __construct (작업 $ 작업)
    {
        $ this-> 작업 = $ 작업;
        $ this-> 새로운 스택 = \ SplStack ();
    }
    
    공용 기능 스케줄 ()
    {
        $ 코 루틴 = $ this-> task-> getCoroutine ();
        $ 값 = $ coroutine-> 전류 ();
 
        $ 상태 = $ this-> handleSystemCall ($ 값);
        경우 ($ 상태 == 자기 :: SCHEDULE_CONTINUE!) 반환 $ 상태;
 
        $ 상태 = $ this-> handleStackPush ($ 값);
        경우 ($ 상태 == 자기 :: SCHEDULE_CONTINUE!) 반환 $ 상태;
 
        $ 상태 = $ this-> handleAsyncJob ($ 값);
        경우 ($ 상태 == 자기 :: SCHEDULE_CONTINUE!) 반환 $ 상태;
 
        $ 상태 = $ this-> handelYieldValue ($ 값);
        경우 ($ 상태 == 자기 :: SCHEDULE_CONTINUE!) 반환 $ 상태;
 
        $ 상태 = $ this-> handelStackPop ();
        경우 ($ 상태 == 자기 :: SCHEDULE_CONTINUE!) 반환 $ 상태;
 
 
        TaskStatus를 반환 :: TASK_DONE을;
    }
 
    공개 isStackEmpty 함수 ()
    {
        반환 $ this-> stack-> IsEmpty 함수 ();
    }
 
    개인 기능 handleSystemCall ($ 값)
    {
        경우 (시스템 콜 instanceof를! $ 값) {
            자기를 반환 :: SCHEDULE_CONTINUE을;
        }
    }
 
    개인 기능 handleStackPush ($ 값)
    {
        경우 (\ 발전기 instanceof를! $ 값) {
            자기를 반환 :: SCHEDULE_CONTINUE을;
        }
 
        $ 코 루틴 = $ this-> task-> getCoroutine ();
        $ this-> stack-> 푸시 ($의 코 루틴);
        $ this-> task-> setCoroutine ($ 값);
 
        TaskStatus를 반환 :: TASK_CONTINUE을;
    }
 
    개인 기능 handleAsyncJob ($ 값)
    {
        만약 (! is_subclass_of ($ 값, 비동기 :: 클래스)) {
            자기를 반환 :: SCHEDULE_CONTINUE을;
        }
 
        $ 부가가치> ([$이 'asyncCallback'])을 실행;
 
        TaskStatus를 반환 :: TASK_WAIT을;
    }
 
    공용 기능 asyncCallback ($ 응답 $ 예외 = NULL)
    {
        ($ 예외 경우! == 널 (null)
            \ 예외 instanceof를 && $ 예외
        ) {
            $ this-> throwException ($ 예외, TRUE);
        } 다른 {
            $ this-> task-> 전송 ($ 응답);
            this-> task-> 실행 $ ();
        }
    }
 
    개인 기능 handelYieldValue ($ 값)
    {
        만약 (! $ this-> task-> 유효한 ()) {
            자기를 반환 :: SCHEDULE_CONTINUE을;
        }
 
        $ RET = $ this-> task-> ($ 값)를 전송;
        TaskStatus를 반환 :: TASK_CONTINUE을;
    }
 
 
    전용 기능 handelStackPop ()
    {
        경우 ($ this-> isStackEmpty ()) {
            자기를 반환 :: SCHEDULE_CONTINUE을;
        }
 
        $ 코 루틴 = $ this-> stack-> 팝업 ();
        $ this-> task-> setCoroutine ($의 코 루틴);
 
        $ 값 = $ this-> task-> getSendVal ();
        $ this-> task-> 전송 ($ 값);
 
        TaskStatus를 반환 :: TASK_CONTINUE을;
    }
 
    공공 기능 throwException ($ 전자, $ isFirstCall = false)를
    {
        경우 ($ this-> isStackEmpty ()) {
            $ this-> task-> getCoroutine () -> 던져 ($ 전자);
            반환;
        }
 
        {시도
            경우 ($ isFirstCall) {
                $ 코 루틴 = $ this-> task-> getCoroutine ();
            } 다른 {
                $ 코 루틴 = $ this-> stack-> 팝업 ();
            }
 
            $ this-> task-> setCoroutine ($의 코 루틴);
            $ coroutine-> 던져 ($ 전자);
 
            this-> task-> 실행 $ ();
        } 캐치 (\ 예외 $ 전자) {
            $ this-> throwException ($ 전자);
        }
    }
}
방법은 스케줄러 작업이 현재 코 루틴을 얻을 예약 할 수 있으며, () 메소드는 현재에 의해 중단 점의 현재 값을 반환하고 반환 값을 처리하는 다섯 개 가지 방법을 전화를 켜십시오.
1 : 쇼핑 시스템 호출
반환 값은 오브젝트 시스템 호출 유형 인 경우 시스템 콜 등 killTask ​​조작으로 실행되며, 시스템 호출이 우선적이다.
2 : 상점 스택 푸시
함수 B의 함수 호출은 다음 함수가 서브 루틴 (서브 루틴)의 함수라고 B, 그러나 코 루틴처럼 일반 전화를 작동 할 수 없다.
() 함수를 funcA
{
    () funcB를 리턴;
}
 
) (GENA를 작동
{
    수율 genB ();
}
funcA funcB ()에서, funcB는 실행 결과를 반환하지만 GENA에서 수율 genB ()는, 발전기 객체보다는 Genb 실행의 최종 결과를 회신한다. genB 실행 결과가 genB 예정 할 필요가 원하지만, 사용의 코 루틴 스택을 달성하기 위해 일반 함수 호출처럼 코 루틴을하기 위해, 그래서 그는 또한, () genD () 코 루틴은 중첩 genB genC가있을 수 있습니다.
그림

스케줄러 GENA 리턴 값 생성기의 인스턴스 (상위 코 루틴)을 취득 할 때, 상술 한 바와 같이, 상위 스케쥴러 코 루틴 밀어서 다음 서브 코 루틴 작업 할당, 스케줄링 서브 코 루틴을 계속할 것이다. 등 마지막 서브 코 루틴은 다음 팝업을 시작 반환 될 때까지 스택은 연속적으로 코 루틴을 제거
 
3 : handleAsyncJob
handleAsyncJob 핵심 코 루틴 일정입니다
개인 기능 handleAsyncJob ($ 값)
    {
        만약 (! is_subclass_of ($ 값, 비동기 :: 클래스)) {
            자기를 반환 :: SCHEDULE_CONTINUE을;
        }
 
        $ 부가가치> ([$이 'asyncCallback'])을 실행;
 
        TaskStatus를 반환 :: TASK_WAIT을;
    }
 
    공용 기능 asyncCallback ($ 응답 $ 예외 = NULL)
    {
        ($ 예외 경우! == 널 (null)
            \ 예외 instanceof를 && $ 예외
        ) {
            $ this-> throwException ($ 예외, TRUE);
        } 다른 {
            $ this-> task-> 전송 ($ 응답);
            this-> task-> 실행 $ ();
        }
    }
리턴 값이 코 루틴을 예정이면 비동기 서브 클래스를 상속 또는 비동기 메소드 실행 실행할 때 인스턴스 Asycn 인터페이스를 구현한다. 여기서, 데이터베이스 쿼리 mysqli 클래스를 예를 들어.
    공공 기능을 실행 (호출 $ 콜백)
    {
        $ this-> 콜백 = $ 콜백;
        $ SERV = ServerHolder :: getServer ();
        $ serv-> 태스크 ($ this-> SQL -1 [$이 'queryReady']);
 
    }
 
    공공 기능 queryReady (\ swoole_http_server의 $의 SERV, $ TASK_ID, $ 데이터)
    {
        $ queryResult = 때 unserialize ($ 데이터);
        $ 예외 = NULL;
        경우 ($ queryResult->의 errno! = 0) {
 
            $ 예외 = 새로운 \ 예외 ($ queryResult-> 이상);
        }
        call_user_func_array ($ this-> 콜백 [$ queryResult, $ 예외]);
    }
 
비동기 작업이 완료된 후에는 콜백 함수를 실행 방법의 수행 방법 Mysqli 클래스는 비동기 swoole_task 비동기 적으로 실행 된 SQL swoole_task로 동작 실행 방법 queryReady 후 실행을 시작할 $ this- 스케줄러 asyncCallback 전에, 상기 방법은 송신의 이상 검출 후에 실행된다 전달) (> 파싱 후 콜백 데이터를 반환 비동기 적으로 수행 () 메소드는 비동기 실행 결과 계속 중단 보낸다 실행.
비동기 동작은 결과를 리턴위한 handleAsyncJob 기다리지 않고, 다시 Task-의 상부에 직접 TASK_WAIT 복귀 신호> run () 메소드가 알 수있는 TASK_WAIT 신호는 run () 메소드가 null 반환 원인 현재 작업자의 스케줄링 흐름도 공개 도에 도시 된 바와 같이,
그림

4 : handleYieldValue
개인 기능 handelYieldValue ($ 값)
    {
        만약 (! $ this-> task-> 유효한 ()) {
            자기를 반환 :: SCHEDULE_CONTINUE을;
        }
 
        $ RET = $ this-> task-> ($ 값)를 전송;
        TaskStatus를 반환 :: TASK_CONTINUE을;
    }
 
리턴 값이 비동기 호출이나 발전기도 아닌 특정 수율, 그것이 완료하면 (완료되었는지 여부)에 전류 발생기가 유효한지 여부를 판정하는 경우, 스케쥴링을 계속 아래 handleStackPush 방법을 수행 달리 즉 Task_Continue 스케줄링 계속 돌아가 그는 발전기 수율 여러 번, 반환 값은 궁극적으로 최종 수율을 취할 것이라고 말했다.
5 : 쇼핑 스택 푸시
위의 단계는 판정 할 때 $ This-> task-> 먼저 STAC가 null, 비어 확인 코 루틴 스택 팝 동작을 제어하기위한 방법을 수행한다 ()은 현재 시간이 발전기의 완료 전에 유효한 부모 팝 코 루틴, 그리고 코 루틴의 전송의 현재 값을 반환하는 경우 () 부모 코 루틴 실행이 계속 중단합니다.
어디 코 루틴의 장점
첫째 IO 요구가 발생하면, 동기 작업이 IO 반환을 기다리고 현재 요청 블록의 원인이됩니다, 요청이 IO의 작업자에 의해 점령되었다는 swoole에 반영.
그림

사용자가 수동으로 수율에 의해 중단 차단 된 수있는 코 루틴 스케줄링을 사용하는 경우 근로자의 직업을 공개하는 것은 다른 요청을 처리하는 동안 그러나, 비동기 작업을 swoole_task 언급.
후에 실행되면 비동기 처리 스케줄의 끝은 계속된다.
그림

참고 PHP는 코 루틴에만 책임을 중단 비동기 작업이 Swoole_task 완료

추천

출처www.cnblogs.com/winner192/p/11704147.html