이 글은 번역된 글입니다. 원주소는 https://stitcher.io/blog/fibres-with-a-grain-of-salt
소금이 들어간 섬유
그래서 글을 쓰려고 합니다. PHP 8.1에서 Fiber를 사용하는 방법에 대한 심층적인 블로그 게시물입니다. 기본적인 예부터 시작하여 처음부터 설명하겠습니다. 아이디어는 비동기 HTTP 요청을 보내고 파이버를 사용하여 병렬로 처리하는 것입니다.
하지만 가지고 놀면서 "Fiber API는 애플리케이션 수준 코드에서 직접 사용해서는 안 됩니다. Fibers는 더 높은 수준의 흐름 제어 API를 생성하기 위해 기본적이고 낮은 수준의 흐름 제어 API를 제공합니다."라는 RFC의 말이 농담이 아니라는 것을 알게 되었습니다. 레벨 레벨 추상화"는 애플리케이션 코드에서 사용됩니다.
그래서 이 길을 따라가서 일을 지나치게 복잡하게 하기보다는 파이버 개념이 무엇인지, 왜 애플리케이션 코드에서 거의 사용할 수 없는지, 그리고 비동기식 PHP를 정확히 어떻게 사용할 수 있는지에 대해 논의하겠습니다.
먼저, 약간의 이론입니다.
세 개의 HTTP 요청을 보내고 결합된 결과를 처리한다고 가정해 보겠습니다. 이를 수행하는 동기식 방법은 첫 번째 응답을 보내고 응답을 기다린 다음 두 번째 응답을 보내고 기다리는 등의 방식입니다.
이러한 프로그램 흐름을 표현하기 위해 가능한 가장 간단한 다이어그램을 사용하겠습니다. 이 차트는 시간이 지남에 따라 위에서 아래로 읽어야 합니다. 각 색상은 HTTP 요청을 나타냅니다. 각 요청의 색상 부분은 실행 중인 실제 PHP 코드, 작업을 수행하는 서버의 CPU를 나타내며, 투명한 블록은 대기 시간을 나타냅니다. 요청은 네트워크를 통해 전송되어야 하며 다른 서버는 이를 처리하여 전송해야 합니다. 응답이 도착해야만 다시 작동할 수 있습니다.
이것은 동기 실행 프로세스입니다: 전송, 대기, 처리, 반복.
병렬 처리의 세계에서는 요청을 보내지만 기다리지 않습니다. 그런 다음 다음 요청을 보내고 또 다른 요청을 보냅니다. 그런 다음에만 모든 요청을 기다립니다. 기다리는 동안 우리는 요청 중 하나가 완료되었는지 주기적으로 확인합니다. 이런 경우에는 즉시 처리해드릴 수 있습니다.
대기 시간을 더 최적으로 사용하기 때문에 이 접근 방식이 어떻게 실행 시간을 줄이는지 확인할 수 있습니다.
Fibers는 이러한 병렬 실행 경로를 보다 효율적으로 관리할 수 있게 해주는 PHP 8.1의 새로운 메커니즘입니다. 생성기와 를 사용하면 이미 수율이 가능하지만 파이버는 이 사용 사례에 맞게 특별히 설계되었으므로 상당한 개선이 이루어졌습니다.
각 요청에 대해 Fiber를 생성하고 요청이 전송된 후 Fiber를 일시 중지합니다. 세 개의 파이버를 모두 생성한 후에는 이를 반복하여 하나씩 복원합니다. 이를 통해 파이버는 요청이 완료되었는지 확인하고 그렇지 않은 경우 다시 일시 중지합니다. 그렇지 않으면 응답을 처리하고 결국 완료할 수 있습니다.
파이버는 프로그램 실행 흐름의 격리된 부분을 시작, 일시 중지 및 재개하는 메커니즘입니다. 파이버는 "그린 스레드"라고도 알려져 있습니다. 동일한 프로세스 내에 실제로 존재하는 스레드입니다. 이러한 스레드는 운영 체제가 아니라 런타임(우리의 경우 PHP 런타임)에 의해 관리됩니다. 이는 일부 형태의 병렬 프로그래밍을 관리하는 비용 효율적인 방법입니다.
그러나 진정한 비동기식 기능은 추가되지 않습니다. 모든 파이버는 동일한 PHP 프로세스에 있으며 한 번에 하나의 파이버만 실행할 수 있습니다. 이는 이를 반복하고 기다리는 동안 확인하는 주요 프로세스입니다. 이 루프를 종종 "이벤트 루프"라고 합니다.
병렬화의 어려운 부분은 파이버나 생성기를 루프하는 방법이나 사용하려는 메커니즘이 아니라 작업을 시작하고 이를 외부 서비스에 전달하고 원할 때만 수행할 수 있는 것입니다. Non-Blocking 방식으로 결과를 확인하는 시간입니다.
보세요, 이전 예에서는 요청을 보낸 다음 원할 때 응답을 확인할 수 있다고 가정했지만 실제로는 말처럼 쉽지 않습니다.
맞습니다. I/O를 처리하는 대부분의 PHP 함수에는 이러한 비차단 기능이 내장되어 있지 않습니다. 실제로는 몇 가지 기능만이 이를 수행하고 이를 사용하는 것은 번거롭습니다.
비차단으로 설정할 수 있는 소켓의 예는 다음과 같습니다.
[$read, $write] = stream_socket_pair( STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP ); stream_set_blocking($read, false); stream_set_blocking($write, false);
stream_socket_pair()를 사용하면 양방향 통신에 사용할 수 있는 두 개의 소켓이 생성됩니다. 보시다시피 stream_set_blocking()을 사용하여 액세스할 수 있습니다.
세 개의 요청을 보내는 예제를 구현한다고 가정해 보겠습니다. 소켓을 사용하여 이를 수행할 수 있지만 그 위에 HTTP 프로토콜을 직접 구현해야 합니다. 이것이 바로 광섬유와 소켓을 사용하여 HTTP GET 요청을 보내는 방법을 보여주기 위해 Reddit에서 작은 개념 증명을 공유한 사용자인 nox7이 한 일입니다. 정말로 애플리케이션 코드에서 이 작업을 수행하시겠습니까?
적어도 나에게는 대답이 "아니요"입니다. 이것이 바로 RFC가 경고하는 내용입니다. 저는 기분이 상하지 않습니다. 대신 기존 비동기 프레임워크 중 하나인 Amp 또는 ReactPHP를 사용하는 것이 좋습니다.
예를 들어 ReactPHP를 사용하면 다음과 같이 작성할 수 있습니다.
$loop = React\EventLoop\Factory::create(); $browser = new Clue\React\Buzz\Browser($loop); $promises = [ $browser->get('https://example.com/1'), $browser->get('https://example.com/2'), $browser->get('https://example.com/3'), ]; $responses = Block\awaitAll($promises, $loop);
与手动创建套接字连接相比,这是一个更好的示例。这就是 RFC 的意思:应用程序开发人员不需要担心纤程,它是 Amp 或 ReactPHP 等框架的实现细节。
不过,这给我们带来了一个问题:与我们已经可以用发电机做的事情相比,纤维有什么好处?RFC 是这样解释的:
与无堆栈生成器不同,每个 Fiber 都有自己的调用堆栈,允许它们在深度嵌套的函数调用中暂停。声明中断点的函数(即调用 Fiber::suspend())不需要更改其返回类型,这与使用 yield 的函数必须返回 Generator 实例不同。
Fiber 可以在任何函数调用中挂起,包括那些从 PHP VM 内部调用的函数,例如提供给 array_map 的函数或迭代器对象上的 foreach 调用的方法。
很明显,纤程在语法和灵活性方面都有显着的改进。但与 Go 及其“ goroutines ”相比,它们还不算什么。
要使异步 PHP 在没有框架开销的情况下成为主流,仍然缺少许多功能,而 Fiber 是朝着正确方向迈出的良好一步,但我们还没有做到这一点。
所以就是这样。如果您不是 Amp、ReactPHP 或较小的异步 PHP 框架的维护者,那么实际上没有什么可说的。也许更多的框架或库将开始合并它们?
同时,还有Swoole——一个 PHP 扩展,它实际上将几个核心功能修改为非阻塞。Swoole 本身是一个中文项目,在涉及英语时通常没有很好的文档记录,但最近 Laravel宣布与它进行第一方集成。也许这是将 PHP 推向更异步模型的更好策略:可选择将 Swoole 或其他扩展与 Laravel 和 Symfony 等框架集成?
위 내용은 PHP8.1의 새로운 기능 설명: 소금 한 알갱이가 함유된 섬유의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!