PHPでマルチタスクに戻る

私の意見では、PHP言語でのマルチタスキングの状況を完全に憂鬱にして、この記事を書くようになりました。

ほとんどのプログラマーは、PHPにはマルチタスクがないため、試してみる必要はないと言います。ブレードの少ないものは、多くのスクリプトを実行することで何らかの形で変質しようとします。



この記事は、ほとんどすべてのプログラミング言語でマルチタスクを実装する方法のアイデアを示すことを目的としています。

いわば、概念実証。

彼らが言うように、新しいものはすべて忘れ去られています。



このメソッドの完全な実装はありますが、既成のソリューションを提供しないことをすぐに警告します。

ほとんどのプログラミング言語、特にPHPでマルチタスクを編成することの問題は何ですか?



簡単な例を考えてみましょう。



一定時間待機する関数を作成する必要があります。

function wait($delta) { $time=microtime(1)+$delta; while($time <= microtime(1)) {} }
      
      







すべてが熊手に似ていますが、問題が発生します-この関数は、指定された時間が経過するまで制御を返しません。

さて、サイクルから抜け出して、再びそこに戻ることができたら...

原則として、この機能はタスクと見なすことができます。問題は、そのようなタスクを2つ同時に起動できないことです。

そして、待機機能と待機タスクの違いは何ですか? 本質的には何もありません。

どのタスクも1つの関数として記述できますが、関数をタスクにするものは何ですか?

そう! タスクはイベント処理アルゴリズムです。 これが実際に関数をタスクにするものです。

そして、タスクはほとんど何をしますか? 再び推測-ある種のイベントを待っています。 したがって、待機せずに待機する方法を理解する必要があります。

問題は何ですか? 少し違った見方をしましょう。



実際、タスクは有限状態マシンとして表すことができ、この例ではこのマシンには3つの状態しかありません。

これが必要なものです。



 function wait($delta) { switch($state) { case 'init': $time=microtime(1)+$delta; $state='wait'; break; case 'wait': if($time <= microtime(1)) { $state='exit'; } break; case 'exit': //      //        case 'wait',     break; } }
      
      





この説明により、関数がすぐに制御に戻り、何も待たないことが明らかです。

関数の最初の呼び出しが常に$ state = 'init'であるとします。

この関数を定期的に呼び出すと、すべての状態を通過しますが、

彼女は時間のない状態ではありませんでした。実際、時間はかかりません。



$状態変数を初期化する方法、関数呼び出し間でローカル変数を保存する方法、このタスクを呼び出す方法、およびその実行を停止する方法の問題を解決することは残っていますか?



通話から始めましょう。

実行するタスクを含む配列を取得しましょう

 $tasks=array();
      
      







次に、タスクの作成は、この配列に必要なデータを追加することになります。

簡単にするために、タスクが受け取るパラメーターは1つだけだとします。 実際、これは十分ですが、あまり便利ではありません。

 function startTask($name,$param) { global $tasks; //          $t=array( 'name'=>$name, 'param'=>$param, 'local'=>array('state'=>'init',), //      'init' ); //     $tasks $tasks[]=$t; //  id  end($tasks); $id=key($tasks); return $id; } //         function task_end($id) { global $tasks; unset($tasks[$id]); } //         function poll() { global $tasks; foreach($tasks as $id=>$p) { call_user_func($p['name'],$id,$p['param']); } } //     wait //          $id //         function wait($id,$delta) { global $tasks; $p=&$tasks[$id]; $local=&$p['local']; $state=&$local['state']; switch($state) { case 'init': $local['time']=microtime(1)+$delta; $state='wait'; break; case 'wait': if($local['time'] <= microtime(1)) { $state='exit'; } break; case 'exit': //      //        case 'wait',     task_end($id); break; } } //     $i=5; while($i--) { startTask('wait', mt_rand(10,100)/100); } //     wait    ,          //        while(count($tasks)) { poll(); //          //             usleep //           poll. usleep(10000); //  10  } echo 'done';
      
      







$ tasks [$ id] ['name']および$ tasks [$ id] ['param']を変更することにより、タスクが

次のループで現在の関数の代わりに別の関数を実行するように強制します。 つまり 機能は異なりますが、タスクは同じままです。



このメカニズムを使用するためのより便利な機能の方向で、さらなる開発が可能です。

たとえば、転送されるパラメータの数に制限はなく、現在のタスクのサブタスクとして別のタスクを呼び出しますが、これらのメカニズムの実装は関心のある読者に任せます。



それはすべて非常に高速で動作します。

そして、上記のすべてが既成のソリューションではなく、アプローチ自体の純粋なデモンストレーションであることに注意してください。

しかし、そのアプリケーションは大きなチャンスを切り開きます。 たとえば、タスクとして設計されたmulti_curlまたはソケットを使用すると、多くの並列ダウンロードタスクを実行できますが、それぞれが独自の結果ハンドラーとデータを操作するための独自のロジックを持つことができ、さらに、同時に他のタスクが他のことを実行できます。



デーモンはPHPで作成でき、ハードウェアドライバでも作成できます。

たとえば、プロジェクトの1つでは、デーモンはCOMポートで複数のデバイスを提供し、それぞれが独自のデータ交換プロトコルを持ち、外部クライアントのTCPサーバーとして機能し、中央サーバーのクライアントとして機能し、すべての支払い端末管理ロジックを実装し、同時に3%しか占有しませんでしたプロセッサリソース。

そして、これらはすべて、実行中の1つのスクリプトだけで実行されました。



マルチタスクを使用すると、実装が非常に簡単になります。



一部の操作に多くの時間がかかる場合があります(他の操作の速度の基準により)。

次に、それらを外部プロセスとして実行することをお勧めしますが、同時に、起動と実行の制御をタスクとして実行します。



同様の例の実作業データを示すデモ、

http://tester.in/rt/task_test.phpにあります。



All Articles