1. ホーム
  2. Web プログラミング
  3. PHP プログラミング
  4. phpのヒント

PHPのタイマーに特化した実装例

2022-01-15 20:10:03

プリアンブル

タイマーには、午前3時の日報のように一定時間ごとに定期的に実行されるものと、メンバーがシステムにログインした5分後に日次ログインボーナスを発行するように、指定時間(1回)後に実行されるものが一般的である。この2つのケースに対応するのが、シェルの cron at コマンドを使用します。 JavaScript の中に setInterval setTimeout 関数は、(厳密に言えば) setInterval が定期的な場合は、指定した時点の実行を自分で処理する必要があります)。

ウェブ開発を行うPHPプログラマーは、JavaScriptの2つのタイマー関数に精通しているはずですが、PHPレベルに戻ると、ちょっとばかばかしいですね。PHP には sleep が、(ビルトインの)タイマー関数が用意されていない。 sleep 関数でかろうじてできますが、その間にプロセスがブロックされて何もできなくなる(または無応答になる)ことになります。なぜPHPはTimer関数を提供しないのでしょうか?

その理由

{その理由は、制御された常駐メモリ環境がないことです。 個人的には、PHPがWeb開発でタイマーを使えない本質的な理由は、制御可能な常駐メモリ実行環境がないことだと思います。CGIモードでは、プロセスはスクリプトを実行した後に直接終了するので、指定した時刻にタスクを実行することは期待できません。PHP-FPMモードでは、プロセス(の大部分)はメモリ上に常駐していますが、制御することはできません。

制御不能とは、PHPを実行するプロセスはPHPのコードの影響を受けず、プロセスのエントリーポイントや終了時刻は追加プログラムによって制御されることを意味します。たとえば、FPM モードでは、PHP スクリプト exit ,

die
functions only interrupt the execution of the script and have no particular impact on the process executing the script (except for memory leaks.) The script written by the PHP developer is the execution body of the process and is offloaded from the execution context of the process when it is finished. In this case, the timing of the execution of the PHP script is still externally driven, and without external requests the PHP code lies peacefully on the hard disk, doing nothing, and timing tasks.
Since PHP is mainly oriented to web development, this execution mode of PHP is stable and reliable, and the development efficiency is fast. For example, eliminating the step of resource release avoids a lot of work and potholes in development. Consider that changing the time zone, character encoding, etc. in some third-party library code is not yet reverted, and will almost certainly lead to problems with subsequent requests in a resident memory runtime environment. But in FPM mode, such pits are inadvertently tripped directly, saving a lot of debugging time and making a not insignificant contribution to the programmer's preservation of his hairline.
The problem is understood, so how to use a timer to execute a timed task in PHP?
A dangerous practice
In a web environment, PHP scripts have a timeout by default. Removing the timeout setting allows the program to keep running in the background (if the process does not exit). For example, the following code continues to run in the background after responding to a request and outputs the time to the file every five seconds.
# test.php

set_time_limit(0); # Remove the timeout setting so the script can run forever

 

echo 'This is a background run forever script. now you can leave me alone.';

 

fastcgi_finish_request(); # end the current 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);

request
http://localhost:8080/test.php
After monitoring the file, the
/tmp/out.dat
file, you will see that there is constant output, regardless of whether the client disconnects, closes the browser, or restarts the computer (you cannot restart the server). This means that the program is executing all the time and is also implementing the timer functionality we want. If we put the
sleep
to
usleep
time_nanosleep
and also implement microsecond and nanosecond timers, wouldn't that be nice?
In practice, you should try to avoid implementing timers in this way, not only because it is inefficient, but also slightly dangerous. One reason is that each request takes up one process, and 100,000 requests require 100,000 processes, which basically leads to system crashes or no response to subsequent requests; in addition, if you open a session but forget to call
session_write_close
If you open the session, but forget to call {{code session_write_close}, it will cause subsequent requests from the same user to be hung (session is in a locked state when it is active, so not closing the session will cause subsequent processes to be unable to open the session).
Web development should be as fast as possible to respond to user requests. Forcing a timer in this way in web development will leave the entire web application in an unstable, unreliable or unpredictable state. Mencius said: Know and act prudently, a gentleman does not stand under a dangerous wall. Unreliable practices should be avoided as much as possible, and by the way, avoid taking the blame and dumping.
Next take a look at the proper posture for using timers in PHP.
The correct posture
The PHP implementation of timers can be summarized simply as follows.
using scheduling tools such as cron, Jenkins, etc. to do periodic timed tasks (either executing scripts or requesting a certain URL).
one-time execution tasks cast to third-party programs for execution via message queues, databases, etc.
simulating timed tasks like WordPress, but keeping in mind that this approach relies on client requests and needs to handle process concurrency on its own.
Run PHP programs using a memory-resident type approach, i.e. CLI mode.
Except for the third approach, all other ways are recommended, so please combine the specific solutions with your actual needs. As a PHP programmer, of course, it is still preferred to do it with PHP, i.e. CLI mode.
CLI mode
In all conscience, CLI mode allows PHP to expand its scope of play quite a bit. In CLI mode, the entry point of the program is the script, and the code can be resident in memory, with the process completely controlled by the PHP code. In this form, there are various ways to play with the implementation of timers. In this article, we list a few ways to do this.
Using
swoole
,
workerman
and other frameworks with built-in (high-precision) timers.
using multi-process (pool)/multi-thread (pool) technology (
pcntl
,
pthreads
(extensions are only available in CLI mode).
Handling signals such as tick or alarm.
Use
libevent
,
libev
and other event-driven libraries.
sleep
Add a loop or implement your own event loop.
If you want to toss it, you can use the 2-5 solution yourself, but if you don't want to toss it
swoole
swoole
workerman
and other frameworks are preferred, stable and reliable.
Summary
Distinguishing between HTTP requests and tasks makes it easy to implement timed tasks. Whether you use PHP to implement it or not is a different story. Of course, as the preferred language for web development, PHP is a breeze to implement timed tasks.
This article about the concrete implementation of PHP timer is introduced to this, more related PHP timer content please search the previous articles of the Codedevlib or continue to browse the following related articles hope you will support the Codedevlib more!

# test.php

set_time_limit(0); # Remove the timeout setting so the script can run forever

 

echo 'This is a background run forever script. now you can leave me alone.';

 

fastcgi_finish_request(); # end the current 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);