質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

5回答

10393閲覧

○秒ごとに実行する処理について

hot-lemoned

総合スコア63

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

1クリップ

投稿2018/10/23 01:21

前提・実現したいこと

現在PHPの勉強中です。

PHPで一定時間ごとに実行するような処理を書いています。
現在の自分で書いたコードでもやりたいことはできているのですが、
とても無駄のある書き方だなと思っており、
もう少し簡素化できないかと思い質問させていただきました。
こんな風に書けばよいとか、このサイトを見ればよいとかでもよいので、
アドバイスをいただけたらありがたいです。

処理の内容によって一定時間ごとに実行できないかもしれないというのは、
ひとまず無視してください。

もしこのような内容が不適切であればコメントいただければ取り下げさせていただきます。
よろしくお願いいたします。

該当のソースコード

PHP

1<?php 2$debug = 1; 3$counter = 0; 4 5while(true){ 6 //echo "カウンター:".$counter.PHP_EOL; 7 $startTime = str_replace(".","",microtime(true)); 8 9 //=============== 10 //1秒ごとに実行する内容 11 if(isset($end_exeTime_1) == false ){ 12 $end_exeTime_1 = 0; 13 } 14 $exe_MinTime_1 = $startTime - $end_exeTime_1; 15 $set_exeMinTime = 10000; //1sec=10000 16 if($exe_MinTime_1 >= $set_exeMinTime){ 17 //ここに実行したい処理 18 echo outputTime().PHP_EOL; 19 echo "1秒ごとに実行".PHP_EOL; 20 $end_exeTime_1 = str_replace(".","",microtime(true)); 21 } 22 //=============== 23 24 //=============== 25 //10秒ごとに実行する内容 26 if(isset($end_exeTime_2) == false ){ 27 $end_exeTime_2 = 0; 28 } 29 $exe_MinTime_2 = $startTime - $end_exeTime_2; 30 $set_exeMinTime = 100000; //1sec=10000 31 if($exe_MinTime_2 >= $set_exeMinTime){ 32 //ここに実行したい処理 33 echo outputTime().PHP_EOL; 34 echo "10秒ごとに実行".PHP_EOL; 35 $end_exeTime_2 = str_replace(".","",microtime(true)); 36 } 37 //=============== 38 39 40 $counter++; 41 if(debug == 1){ 42 if($counter >= 100){ 43 break; 44 } 45 } 46 //カウンターリセット 47 if($counter == hexdec("FFFF")){ 48 $counter = 0; 49 } 50 51}//----------while 52 53 54//+++++++++++++++++++++++++++++++++++++++++++ 55function outputTime(){ 56 $unixTime = explode( '.', microtime(true) ); 57 $dispTime = date( 'Y/m/d H:i:s', $unixTime[0] ) . "." . substr( $unixTime[1].'0000', 0 , 3 ); 58 return $dispTime; 59} 60?>

補足情報(FW/ツールのバージョンなど)

MacOS 10.13.6
PHP 7.1.16(cli)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答5

0

ベストアンサー

sleep()で実行すると処理に要した時間も加算されて、だんだん時間が伸びてしまう

「1秒ごとの処理」を始める直前のmicro秒を覚えておき、
処理が終わった時にもう一度micro秒を取って、
1秒から処理にかかった時間を差し引いたmicro秒の分だけを、
usleep()でsleepしてあげればよいです。

処理に0.1秒かかったとして、0.9秒usleepとか。


処理毎に毎回計測すると暴れないかわりに小さなズレは蓄積するので、
最初に取った時刻からn秒後を基準として余りをusleepする例を書いてみました。

php

1<?php 2date_default_timezone_set('Asia/Tokyo'); 3 4$start = microtime(true); 5for($i=1; $i<=100; $i++){ 6 7 func1(); 8 if( ($i % 10) == 1){ 9 func10(); 10 } 11 12 $end = microtime(true); 13 $n = (($start + $i) - $end)*1000*1000; 14 if( $n > 0 ){ 15 usleep( $n ); 16 } 17} 18 19 20//+++++++++++++++++++++++++++++++++++++++++++ 21function outputTime(){ 22 $unixTime = explode( '.', microtime(true) ); 23 $dispTime = date( 'Y/m/d H:i:s', $unixTime[0] ) . "." . substr( $unixTime[1].'0000', 0 , 3 ); 24 return $dispTime; 25} 26 27function func1() 28{ 29 echo outputTime().PHP_EOL; 30 echo "1秒ごとに実行".PHP_EOL; 31 32 usleep( 200*1000 ); // 0.2秒かかるとする 33} 34function func10() 35{ 36 echo outputTime().PHP_EOL; 37 echo "10秒ごとに実行".PHP_EOL; 38 39 usleep( 300*1000 ); // 0.3秒かかるとする 40} 41

お節介かもですが勉強中ということですので、敢えてアドバイスさせてください。

質問欄に提示されていらっしゃるソースコードですと、
「1秒ごとの処理」を行う時間がくるまで全力でループを回り続けています。
こうするとCPUは無駄に回り続け、他のプロセスに割り当てるられるはずだった
CPUリソースを浪費してしまいます。
具体的に言うと、仮にCPUが1個のコンピュータであればCPUのロードが100%になってしまいます。
実害的には、電力を浪費する、他の処理が重くなる、などです。

このようなコードは、効率が悪い、お行儀が悪い、というレベルよりもう少し罪が重い、
"書いてはならないコード"に該当してしまいます。
ですので、プログラマを目指されているのでしたら、理解されておくべきかなと思います。

対処としては、みなさんがおっしゃっている回答のように、
空ループで時間を潰さずに、時間がくるまでsleepやタイマを使って待ちます。
待っている間はCPUが浪費されません。

投稿2018/10/23 09:54

編集2018/10/24 03:48
taka-saan

総合スコア665

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hot-lemoned

2018/10/24 02:25

回答ありがとうございます。 私の理解力が足りていないのでコードを読み解いていきますので、 少々お時間をください。
hot-lemoned

2018/10/25 00:49

回答ありがとうございました コードの書き方が参考になりました! アドバイスありがとうございます 他の方からも指摘があった通り、確かにphpで書くべきではないと思います… 例えばですが、node.jsやpythonであれば、このような処理は妥当でしょうか? (妥当というのにはいろいろな定義があると思いますが…)
taka-saan

2018/10/25 02:27

私が良くないと指摘しているのは「時間が来るまで全力でループする」実装についてです。 1秒ごとに何かを行うという要件を満たすためにPHPを使うことに関しては、多少の向き不向きはあるにせよ全然問題にしていません。 node.jsやpythonであっても考え方は同じです。同じ様にループするコードを書いてしまえば「書いてはならないコード」になります。
hot-lemoned

2018/10/25 05:08

コメントありがとうございました 話が逸脱してしまいましたので、それ以降は別で質問を挙げさせていただくかもしれません 回答ありがとうございました
guest

0

これって、無限ループさせる前提でしょうか?
個人的には、php にやらせるには筋が悪い処理に思えます。
例外処理等もガチガチに書かねばならなくなるので、php のゆるさ激減ですw

cron にまかせてみるとかすると、元のゆるさに戻せます。
n秒おきにcronを指定
こんなの参考にしてみては?

適当な処理でも、ぐるぐる回してくれて、エラーの時適当にログ吐くように仕組んでおけます。

投稿2018/10/23 08:26

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/10/23 08:27

これと、lock ファイル作る処理を適当に組み合わせて、多重立ち上げを禁止した処理を実際に使用していますが、まぁそこそこ正しく動きますw
hot-lemoned

2018/10/23 09:31

回答ありがとうございます。 はい、基本は無限ループをさせる前提です やっぱりphpには分が悪いですよねw 背景としてはちょうどデモリリースが迫っていて、まだ私がphpなら使えるかなという感じだったので… 実はいただいた内容はcronで実行していました。 そのときは複数の処理をcronに登録していたのですが、1つの処理しか定期的に実行されず、 現在の方式にしてしまいました… (この時なぜ実行されなかったのかは調査せず) cronで実行することも検討してみたいと思います…
退会済みユーザー

退会済みユーザー

2018/10/23 09:59

cron 使用するなら、多重起動だけは気をつけて^^ 雪だるま式にタスクが溜まっちゃうんで。
hot-lemoned

2018/10/23 10:06

ご指摘ありがとうございます いちおう今まではセマフォを利用して排他制御していましたので、 私の理想の形にならないようであれば、そちらも検討したいと思います
guest

0

httpベースの話でしょうか?
httpの場合バッファリングの関係で、サーバー側で実行したタイミングと
クライアント側に表示されるタイミングにずれがあります。
仮にサーバー側で1秒毎に実行を10回やっても
クライアント側では10秒後に1回表示されたりします。
なのでサーバー側での時間を指定した繰り返し処理はあまり現実的ではないと思います。
クライアント側から定期的にajaxで取りに行くなど別の切り口が良いのではないでしょうか?

投稿2018/10/23 01:27

yambejp

総合スコア114771

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hot-lemoned

2018/10/23 07:52

回答ありがとうございます。 httpベース?ではなくて、cliで実行しています。 今回はクライアントは特に関係なくサーバー側だけでの対応の話です。
guest

0

このサイト「タイマーのサンプル」はどうでしょうか?

投稿2018/10/23 01:27

miyakichi

総合スコア297

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hot-lemoned

2018/10/23 07:47

回答ありがとうございます。 Fatal error: Uncaught Error: Class 'EvTimer' not found in 〜 と出力されたのですが、これはPECL?というのをインストールしないと使えないのでしょうか?? 無知で恐縮ですがもしわかればご教授ください。
miyakichi

2018/10/23 10:00

PHP EvクラスはPECL拡張であり、PHPにバンドルされていませんので、PECL拡張モジュールのインストールが必要です
hot-lemoned

2018/10/24 03:27

コメントありがとうございます こんなこと聞いていいかわかりませんが、 下記サイトのソースをビルド?してインストール?すればよろしかったでしょうか? https://pecl.php.net/package/ev
miyakichi

2018/10/24 11:06

すいません。やったことないのでよくわかりません。 新しく、質問すればどうでしょう?
hot-lemoned

2018/10/25 00:40

コメントありがとうございます 派生でこのまま質問してしまい失礼しました インストールできそうなのでやってみてうまくいかなければ、新規質問させていただきます 情報提供ありがとうございました
guest

0

単純にsleep仕込むんじゃダメな感じですかね…?
PHP マニュアル:sleep

投稿2018/10/23 08:08

madoka9393

総合スコア992

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hot-lemoned

2018/10/23 08:20

回答ありがとうございます。 うまく説明ができないのですが、sleep()で実行すると処理に要した時間も加算されて、 だんだん時間が伸びてしまうので今回は見送らせていただきました。 (もし違うよ!という場合にはご指摘ください)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問