Introduction to ReactPHP and asynchronous PHP

자주 비동기 PHP에 대해 이야기 할 때 사람들은 PHP가 이런 종류의 작업에 적합한 도구가 아니라고 말했습니다 우리는 이미 Go 및 NodeJS를 사용하여 PHP 대신 사용하십시오

물론, 당신은 자유 롭습니다 비동기식 해결을 위해 잘 알려진 다른 언어를 사용하십시오 하지만 개발자로서 언어 자체가 케이스 하나 이상의 언어를 스택에 추가하려면 모든 종속성을 설정해야합니다 이 새로운 언어에 맞는 배포 시스템과 전체 생태계를 구성하십시오

이미 PHP 팀과 일하면서 새로운 것을 파헤치는 것이 훨씬 쉬울 것입니다 새 언어로 스택을 확장하는 대신 라이브러리를 사용하십시오 확실히 PHP가 비동기 작업을 해결하기 위해 만들어지지 않았다는 것은 사실입니다 더 많은 목표 대규모의 복잡한 시스템을 구축하는 데 사용할 수있는 프로그래밍 언어가 아니 었습니다 문제가 발생했을 때 자바 스크립트가없고 비동기적인 내용도 없었습니다

이제 완전히 다른 PHP를 사용하게되었습니다 대규모 복합 단지를 구축하기위한 프레임 워크가 있습니다 응용 프로그램과 PHP는 더 이상 요청 응답주기로 제한되지 않습니다 라이브 스트리밍, 다른 API, 다른 클라이언트와의 통합 장수명 콘솔 명령 및 직원이 작업해야하는 요구 사항 매우 빠릅니다 전통적인 동기식 환경에서 프로그램이 하나씩 실행됩니다

우리는 하나의 작업을 시작한 다음 작업이 완료 될 때까지 기다립니다 그때 만 다른 작업을 시작할 수 있습니다 상상하고 예측하기 쉽습니다 그러한 프로그램의 결과 요청 응답주기의 경우이 모델이 작동 할 수 있습니다

좋지만 복잡한 작업에 대해서는 동기식 접근 방식이 약간의 불편을 낳을 수 있습니다 세 가지 다른 데이터 소스와의 통합이 있다고 가정 해 보겠습니다 우리는 그들로부터 데이터를 수집하고,이 데이터를 처리하며 고객에게 돌아갑니다 에서 기존의 동기식 환경에서는 각 소스를 하나씩 요청하고 각각의 응답 시간은 1 초에서 3 초까지 걸립니다 데이터를 수집하기 위해 최소한 3 초를 기다려야합니다

에 비동기로 작업 할 때 우리는 하나의 요청을 기다리는 데 시간을 낭비하지 않습니다 다른 사람들을 시작하기 위해 완료되어야합니다 우리는 이러한 요청을 하나씩 시작합니다 그런 다음 나중에 작업을 마친 후 결과를 수집하기 위해 다시 방문합니다 모든 요청을 기다리는 대신 가장 느린 요청 만 기다려야합니다

그들 여기서 주요 아이디어는 계산이 엄청나게 빠릅니다 I / O와 비교 이는 API의 응답을 기다리는 동안, 데이터베이스 또는 파일 시스템에서 CPU가 수행하는 작업은 없습니다 뭔가하는 대신 유용한 비동기 방식은 논 블로킹 I / O의 아이디어를 사용합니다

우리는 시작한다 비 블로킹 작업이 완료 될 때까지 기다리지 않고 수행 할 수 있습니다 한 번 뭔가 재미있는 일은 우리가 그것에 반응 할 수 있다는 것입니다 우리는 무언가가 있음을 어떻게 알 수 있습니까? 일어난? 그 일이 끝났다고? 그 대답은 "사건들"입니다 이것은 우리가 "이벤트 중심 아키텍처"를 호출하십시오 우리는 특정 사건을 경청하고 그들이 일어날 때 우리는 그들에게 반응하라

우리의 경우 우리는 하나의 스레드에서 실행되는 PHP를 처리합니다 이벤트 큐가 필요한 비동기 프로그램을 만들 수 있어야합니다 이 대기열은 모든 비동기 응용 프로그램의 핵심입니다 우리가 이벤트 루프라고 부르는 것입니다 언제 새 이벤트가 발생하여 대기열에 추가됩니다

다음에 프로그램을 만들 때 thread는, 큐로부터 최초의 이벤트를 취해 아무것도 처리하지 않고, 적절한 이벤트 핸들러 핸들러가 완료되면 쓰레드는 다음으로 돌아 간다 대기열에 있으며 대기 중일 때 발생할 수있는 새 이벤트를 취합니다 그리고 모든 것이 무한 루프에서 발생합니다 어느 순간에 비동기 스레드는 두 가지 모드 중 하나 일 수 있습니다 : "디스패처 모드"와 다음에 처리해야하는 이벤트와 "처리기 모드"를 적절한 이벤트 핸들러

그러나 우리 코드를 제외한 모든 것은 병렬로 실행됩니다 우리의 이벤트 핸들러는 하나씩 실행됩니다 "비동기"는 "병렬"을 의미하지 않습니다 프로그램은 여러 개의 비 블로킹 작업을 시작하기 때문에 더 빠르게 실행됩니다 그들이 끝날 때까지 기다릴 필요가 없습니다

대신 우리는 언제 통보를 받습니까? 재미있는 일이 일어난다 예를 들어, 응답이 수신되고, 파일이 쓰여지고 나서 우리는에 반응 할 수있다 이번 행사 이제 PHP에 대해 이야기 해 보겠습니다 PHP에는 네이티브 도구가 없습니다

비동기 코드를 작성하십시오 우리는 낮은 수준의 물건을 가지고 있지만 그러한 것들은 없습니다 "이벤트 루프", "스트림"및 "약속"과 같은 높은 수준의 추상화 그래서 그러한 reactPHP와 같은 도구가 존재합니다 ReactPHP는 프레임 워크가 아닙니다

그것은 일련의 비동기 PHP를 작성하는 데 사용할 수있는 다양한 구성 요소 모든 구성 요소 PHP로 작성되었습니다 추가 확장 프로그램을 설치할 필요가 없습니다 ReactPHP로 작성된 비동기 코드는 JavaScript와 매우 유사합니다 자주 유일한 차이점은 PHP에서 이벤트 루프가 실행되지 않는다는 것입니다

장면 따라서 명시 적으로 생성하고 실행하는 것이 우리의 임무입니다 예를 들어, 여기에 매우 간단한 JavaScript 코드 : setTimeout () 함수로 일부 실행을 지연합니다 ReactPHP에서 "hello world"와 같은 코드를 출력 할 것입니다 이렇게 생겼어

해당 항목의 생성 및 실행을 제거하십시오 우리는 자바 스크립트에서 가지고있는 것과 거의 같은 코드를 얻는다 ReactPHP에서 비동기 프로세스의 결과를 얻으려면 약속의 개념입니다 나는 우리 중 대부분이 이미 자바 스크립트 세계 약속은 처음에는 알 수없는 자리 표시 자입니다

결과 우리는 수행하는데 약간의 시간이 필요한 작업이 있습니다 이 작업은에 대한 일부 값을 반환 할 수 있습니다 실패 할 수 있습니다 이 작업은 비동기 적으로 실행되므로 즉시 반환 값에 대한 액세스 대신 자리 표시자를 얻은 다음 정의합니다

이 자리 표시자를 실제 가치로 대체하면 어떤 행동을 취하십시오 이는 약속이 세 가지 별개의 상태에있을 수 있음을 의미합니다 이 약속을 되 돌린 연기 된 절차에 따라 "보류 중"상태 프로세스가 아직 실행 중임을 나타냅니다 "이행 됨"은 프로세스가 완료되었음을 의미하며 "거부 됨"은 프로세스가 실패했음을 의미합니다

소비자의 경우 코드는 수행원 약속을 통해 선언적 방식으로 코드를 작성할 수 있습니다 우리는 선언한다 일단 우리가 결과를 얻으면 우리는 어떤 행동을 취합니다 방법 then () 두 개의 인수를받습니다

첫 번째 콜백은 지연된 프로세스가 성공적으로 완료되면 두 번째 프로세스가 실패합니다 우리는 또한 체인 수 있습니다 결과를 처리하기 위해 다른 콜백을 제공합니다 예를 들어, 지연된 프로세스의 결과는 1이고, 우리는 2로 곱하고, 2를 전달합니다 두 번째 콜백에 인수로

다시 우리는 그것을 2 배로 곱한 다음 4 장 인쇄 스트림은 JavaScript에서와 똑같이 보입니다 그들은 우리가 많은 양의 데이터를 청크별로 처리합니다 예를 들어 우리가 몇 기가 바이트 크기의 큰 로그 파일을로드 할 필요가 없습니다 모든 것을 기억으로

대신 스트림을 통해이 파일을 읽을 수 있습니다 새로운 데이터 덩어리가 준비 될 때마다 알림을받습니다 로그의 경우 그것은 읽을 수있는 스트림 파일입니다 서버에 파일을 업로드하는 경우 디스크에 계속 기록하면 쓰기 가능한 스트림이됩니다 소켓 연결 판독 가능하고 기입 가능한 양방향 스트림은 양방향 스트림으로 표현 될 수있다

Streams API는 NodeJS와 매우 유사하게 보입니다 스트림에 무엇인가 쓸 수 있습니다 우리는 특정 사건을들을 수 있습니다 스트림 또한 이벤트 미터입니다 뭔가 흥미로운 것이 내부에서 일어나고, 그 물줄기는 그것에 반응 할 수 있습니다

예를 들어 우리는 "데이터"이벤트에 이벤트 핸들러를 추가 할 수 있습니다 '데이터'이벤트는 매번 발생합니다 읽을 수있는 스트림에는 읽을 수있는 새로운 데이터 청크가 있습니다 '닫기'이벤트는 스트림이 닫힐 때 발생합니다 예를 들어 전체 파일을 읽었습니다

이것들은 기본적인 저수준 추상화, 비동기 암호 ReactPHP 생태계는 또한 많은 다른 고급 구성 요소를 제공합니다 여기에는 저장소, 네트워크 통신, 대기열, 비동기 캐시 및 로그, 다른 스트림 등이 있습니다 코드 이전에 말했듯이 작성된 ReactPHP는 NodeJS와 매우 유사합니다 다음은 매우 간단합니다

모든 문자열에 대해 "hello world"라는 200 개의 응답을 반환하는 웹 서버 들어오는 요청 왼쪽에는 NodeJS 버전이 있으며 ReactPHP는 오른쪽으로 서버를 만들고 지정된 포트에 소켓을 연 다음 서버를 소켓에 연결하고 루프를 실행하십시오 매우 간단한 비동기 웹 서버 PHP로 작성되었습니다 NodeJS 버전과의 유일한 차이점은 우리가 명시 적으로 이벤트 루프를 작성하고 실행하십시오

나머지 코드는 같은 NodeJS로 작성된 비동기 코드가 그것보다 PHP 버전의 코드가 더 깨끗합니다 을 활용하려면 ReactPHP를 사용하면 애플리케이션을 처음부터 다시 작성할 필요가 없습니다 예를 들어 우리는 몇 가지 응용 프로그램을 가지고 컨트롤러에서 우리는 두 다른 출처 그런 다음이 데이터를 수집하고 페이지를 렌더링합니다

우리는 다시 쓸 수 있습니다 이 코드의 유일한 병목 부분 : 동기 HTTP 요청 우리는 이벤트 루프 그런 다음 약속을 반환하는 두 가지 요청을 보낸 다음이 때까지 기다립니다 해결하겠다는 약속

데이터를 수집하고 동기식 흐름을 계속합니다 우리 비동기 적으로 데이터를 수신하지만 페이지를 동 기적으로 렌더링합니다 만약 모든 것이 너무 좋아 보이기 때문에 모든 응용 프로그램을 작성해야합니다 비동기식으로? 그러나 위대한 힘으로 큰 책임이 있습니다 제일 어려운 문제는 통화를 차단하는 것입니다

우리의 코드는 단일 위협, 즉 장기 실행 작업이 전체 루프를 차단합니다 이벤트 루프가 지속적으로 실행되어야합니다 새로운 사건을 경청하고 그들에게 손을 대지 마라 하나의 처리기가 너무 오래 실행되어 나머지 응용 프로그램이 대기합니다 불행히도 대부분의 네이티브 함수와 타사 라이브러리는 처음에는 전통적인 동기 런타임에서 작동하도록 작성되었으며 흐름

모든 네트워크 통신이 루프를 차단할 수 있습니다 요청이 진행되는 동안 우리는 기다렸다 이것이 PDO와 모든 라이브러리를 사용할 수없는 이유입니다 그것 위에 세웠다 PDO는 네트워크 요청을 사용합니다 대신 우리는 스트림 기반 고객

file_exists ()와 같은 모든 기존 파일 시스템 함수를 사용할 수는 없습니다 또는 file_get_contents () 대신 특수 비동기 어댑터를 사용해야합니다 또한 타사 라이브러리를 사용할 때 어떤 기능이 중요한지 알아야합니다 내부에서 사용됩니다

루프를 차단할 수 있는지 여부 비동기 코드에서 통화 차단을 대체하는 대신 다음 규칙을 사용할 수 있습니다 우리가 약속을 사용하는 단일 한 가치를받습니다 우리가 어떤 사람들과 일할 때 스트림을 사용하는 일부 데이터를 지속적으로 푸시하거나 수신하는 API입니다 언제 완전히 비동기식 애플리케이션 작성하기 우리가 직면 할 수있는 문제들

사람들은 종종 PHP에서 불평합니다 어 메모리 누수가 발생합니다 우리는 정말 멋진 최신 버전의 모든 첫 번째 가비지 컬렉터 및 메모리가 누출되지 않습니다 그리고 그것도 문제가 아닙니다 PHP

NodeJS에서 동일한 메모리 문제가 발생할 수 있습니다 긴 메모리 관리 살아있는 프로세스는 개발자의 책임입니다 그것은 당신의 직업입니다 개발자는 메모리를 최적화, 축소 및 제거 할 수 있습니다 장기 실행 스크립트에서 데이터베이스 연결은 시간 종료로 닫힐 수 있습니다

당신은 일종의 구현해야합니다 필요한 경우 점검하고 다시 연결하십시오 오류에 특별한주의를 기울이십시오 손질 전통적으로 각 클라이언트마다 별도의 스레드가 있습니다

와 새로운 요청이있을 때마다 우리는 전체 애플리케이션을 부트 스트랩하고 일부를 실행한다 코드 어떤 것이 실패하면 현재 요청에만 영향을 미칩니다 다른 모든 연결 가능하게 살아있어 비동기 서버로 무언가가 실패 할 때 응용 프로그램이 충돌하고 모든 클라이언트의 연결이 끊어집니다 왜냐하면 비동기 적으로 발생하면 유동의 거동을 예측하기가 어렵습니다

그리고 물론 die () calll을 사용하면 전체 응용 프로그램에서 var_dump () 및 die 중지하면 모든 클라이언트 또는 프로세스가 파괴됩니다 그리고 그 모든 것을 기억하십시오 동기식 응용 프로그램의 클라이언트 또는 프로세스에 일부 공유 전역이 있습니다 상태 그리고 그들은 같은 기억을 공유합니다

따라서 비동기 PHP가 존재하며 라이브입니다 네트워크 통신인지 또는 네트워크 통신인지 여부를 일부 I / O 기다리는 경우 파일 시스템을 차단하고 방해하는 경우 ReactPHP 사용을 고려하십시오 비동기식 접근 방식이 크게 향상 될 수 있습니다 PHP는 당신은 그것에 대해 생각하곤했습니다 스택을 복잡하게 만들 필요가 없습니다

다른 언어로 비동기 작업을 해결할 수 있습니다 아마도 PHP가 할 수 있습니다 쉽게 다룰 수 있습니다 그리고 ReactPHP는 비동기 코드를 작성하는 데 도움을 줄 수 있습니다 그곳에 마법과 관련이 없으며 추가적인 확장이 필요하지 않습니다

그러나 기대하지 마라 ReactPHP를 프로젝트에 추가하면 모든 것이 작동하기 시작합니다 2 배 빠릅니다 이런 식으로 작동하지 않습니다 모든 것을 얻으려면 비동기 코드의 전체 개념을 이해해야합니다

그것으로부터 이익을 얻습니다