PHP가 웹 개발에서 타이머를 사용할 수 없는 근본적인 이유는 제어 가능한 상주 메모리 운영 환경이 부족하기 때문입니다. 첫 번째는 상주 메모리이고 두 번째는 제어 가능합니다. CGI 모드에서는 프로세스가 스크립트 실행 후 바로 종료되며 지정된 시간에 작업이 실행될 것으로 예상할 수 없습니다. PHP-FPM 모드에서는 프로세스가 메모리에 상주하지만 제어할 수 없습니다.
이 튜토리얼의 운영 환경: Windows 7 시스템, PHP 8 버전, DELL G3 컴퓨터
두 가지 일반적인 타이머가 있습니다: 하나는 주기적 타이밍 실행입니다. , 예를 들어 매일 이른 아침 3시에 보고서가 발행되고, 다른 보고서는 지정된 시간(1회) 후에 실행됩니다. 예를 들어 일일 로그인 보상은 회원이 시스템에 로그인한 후 5분 후에 발행됩니다. JavaScript의 setInterval, setTimeout 함수에 해당합니다(엄밀히 말하면 setInterval은 주기적으로 실행되며 지정된 시점의 실행은 자체적으로 처리해야 함).
웹 개발을 하는 PHP 프로그래머는 JavaScript의 두 가지 타이머 기능에 익숙해야 합니다. PHP 수준으로 돌아가면 약간 어리둥절합니다.
PHP에는 절전 기능이 있지만 (내장) 타이머는 없습니다. 기능을 사용할 수 있습니다. 슬립 기능은 거의 할 수 없지만 이 기간 동안 프로세스가 차단되고 다른 작업을 수행할 수 없습니다(또는 응답하지 않게 됨). PHP는 왜 타이머 기능을 제공하지 않습니까?
이유
PHP가 웹 개발에서 타이머를 사용할 수 없는 근본적인 이유는 제어 가능한 상주 메모리 운영 환경이 부족하기 때문입니다. 두 가지 핵심 사항: 첫째, 상주 메모리, 둘째, 제어 가능. CGI 모드에서는 프로세스가 스크립트 실행 후 바로 종료되며 지정된 시간에 작업이 실행될 것으로 예상할 수 없습니다. PHP-FPM 모드에서는 프로세스가 (대부분) 메모리에 상주하지만 제어할 수 없습니다.
Uncontrollable은 PHP를 실행하는 프로세스가 PHP 코드의 영향을 받지 않으며 프로세스의 진입점과 종료 시점이 추가 프로그램에 의해 제어된다는 의미입니다. 예를 들어 FPM 모드에서 PHP 스크립트의 종료 및 다이 기능은 스크립트 실행을 중단할 뿐이며 스크립트 실행 프로세스에 특별한 영향을 미치지 않습니다(메모리 누수 제외). PHP 개발자가 작성한 스크립트는 프로세스의 실행 본문이며 실행 후 프로세스의 실행 컨텍스트에서 언로드됩니다. 이 경우 PHP 스크립트를 실행하는 타이밍은 여전히 외부에 의해 좌우됩니다. 외부 요청이 없으면 PHP 코드는 아무 작업도 하지 않고 조용히 하드 디스크에 놓여 예약된 작업이 됩니다.
PHP는 주로 웹 개발을 지향하기 때문에 PHP의 실행 모드는 안정적이고 신뢰할 수 있으며 개발 효율성이 빠릅니다. 예를 들어 리소스 릴리스 단계를 생략하면 개발 시 많은 작업량과 함정을 피할 수 있습니다. 시간대, 문자 인코딩 등을 변경하고 이를 복원하지 않는 일부 타사 라이브러리 코드를 생각해 보십시오. 상주 메모리 실행 환경에서는 후속 요청에 문제가 발생할 것이 거의 확실합니다. 그러나 FPM 모드에서는 이 함정이 의도치 않게 완화되어 디버깅 시간을 많이 절약하고 프로그래머의 헤어라인 유지 능력에 상당한 기여를 합니다.
이제 문제를 이해했으므로 PHP에서 예약된 작업을 수행하기 위해 타이머를 어떻게 사용합니까?
웹 환경에서 PHP 스크립트에는 기본적으로 시간 초과가 있습니다. 시간 초과 설정을 제거하면 프로그램이 백그라운드에서 계속 실행될 수 있습니다(프로세스가 종료되지 않는 경우). 예를 들어, 다음 코드는 요청에 응답한 후에도 백그라운드에서 계속 실행되어 5초마다 파일에 시간을 출력합니다.
# test.php set_time_limit(0); # 取消超时设置,让脚本可一直运行 echo 'This is a background run forever script. Now you can leave me alone.'; fastcgi_finish_request(); # 结束当前请求 do{ file_put_contents("/tmp/out.dat", "test script, now:" . date("Y-m-d H:i:s") . "\n", FILE_APPEND); sleep(5); }while(true);
http://localhost:8080/test.php 파일에서 <code>/tmp/out.dat
파일을 모니터링하면 클라이언트 연결 끊기, 브라우저 닫기 또는 컴퓨터 재시작 여부에 관계없이 콘텐츠가 지속적으로 출력되는 것을 확인할 수 있습니다(서버는 다시 시작했습니다). 이는 프로그램이 실행되었으며 우리가 원하는 타이머 기능이 달성되었음을 나타냅니다. sleep
을 usleep
또는 time_nanosleep
으로 변경하면 마이크로초 및 나노초 타이머도 구현할 수 있으면 좋지 않을까요? http://localhost:8080/test.php
文件后,监测/tmp/out.dat
文件,会发现不断有内容输出,无论客户端是否断开连接、关闭浏览器或者重启电脑(不能重启服务器)。这说明程序一直在执行,并且也实现了我们想要的定时器功能。如果把sleep
改成usleep
、time_nanosleep
,还能实现微秒、纳秒级定时器,岂不美哉?
实践中应当尽量避免用这种方式实现定时器,不仅因为低效,还略有危险。原因之一是每次请求会占用一个进程,请求十万次需要十万个进程,基本上会导致系统崩溃或后续请求无响应;另外如果打开了session,但是忘记调用session_write_close
session_write_close
를 호출하는 것을 잊어버리면 동일한 사용자의 후속 요청이 중단됩니다. 세션은 활성 상태일 때 잠긴 상태이며 세션을 닫지 못하면 후속 프로세스를 수행할 수 없습니다. 세션을 열려면). 웹 개발에서는 사용자 요청에 가능한 한 빨리 응답해야 합니다. 웹 개발에서 이러한 방식으로 타이머를 강제로 구현하면 전체 웹 애플리케이션이 불안정하고 신뢰할 수 없거나 예측할 수 없게 됩니다. 맹자가 말했다: 군자는 위험한 벽 아래 서지 않는다. 신뢰할 수 없는 관행은 최대한 피해야 하며, 책임을 떠맡거나 전가하는 행위도 피해야 합니다. 다음으로 PHP에서 타이머를 사용하는 올바른 자세를 살펴보겠습니다. 세 번째 방법을 제외한 다른 모든 방법은 실제 필요에 따라 구체적인 계획을 고려하는 것이 좋습니다. 물론 PHP 프로그래머로서 첫 번째 선택은 CLI 모드인 PHP를 사용하는 것입니다.
양심적으로 말하면 CLI 모드를 사용하면 PHP가 공간을 많이 확장할 수 있습니다. CLI 모드에서 프로그램의 진입점은 스크립트이고 코드는 메모리에 상주할 수 있으며 프로세스는 PHP 코드에 의해 완전히 제어됩니다. 이 형식에는 타이머를 구현하는 방법이 많이 있습니다. 이 문서에는 다른 사람들에게 영감을 줄 수 있는 몇 가지 방법이 나와 있습니다.
내장된(고정밀) 타이머가 있는 swoole
및 workerman
과 같은 프레임워크를 사용하세요. 멀티 프로세스(풀)/멀티 스레딩(풀) 기술을 사용합니다(pcntl
, pthreads
확장은 CLI 모드에서만 사용 가능) swoole
、workerman
等框架,内置(高精度)定时器;
使用多进程(池)/多线程(池)技术(pcntl
、pthreads
拓展在CLI模式下才可用);
处理tick或者alarm等信号;
使用libevent
、libev
等事件驱动库;
sleep
加循环或自己实现事件循环。
想折腾的话自己用2-5方案,不想折腾swoole
、workerman
libevent
및 libev
와 같은 이벤트 기반 라이브러리를 사용하여 루프를 추가하거나 구현합니다. 이벤트가 스스로 루프됩니다.
만들고 싶다면 swoole
및 workerman
과 같은 프레임워크를 망치고 싶지 않다면 2-5 계획을 직접 사용하세요. 그들은 안정적이고 신뢰할 수 있는 첫 번째 선택입니다.
위 내용은 PHP에는 왜 타이밍 기능이 없나요?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!