2017年4月6日木曜日

PocketMine-MPでマルチスレッド処理をする!Thread/AsyncTask

こんにちは、haniokasaiです。
誰も、PocketMine-MPのマルチスレッドについてまとめた人がいなかったのでまとめてみます。

イントロ
phpで書かれたpocketmineは重いです。それは、保守のかんたんさと引き換えにそうなっているのでしょうが、特にcurlで外部のapiにアクセスをするものを使うときには全体の処理を遅らせてしまうことでしょう。
そもそも、PMMPのbinには、pthreadが同梱されていますが、単純に使うことはどうやら
できないようです。そこでどうしようかなぁと思ってたら、記憶がうろ覚えなのですが、pocketmine\threadを使うと良いと、おぎわらが教えてくれました。彼は私の夢で何故か一度登場したことがあります。
マルチスレッドについては、検索すればいい説明が読めます。


プラグイン例
https://github.com/haniokasai/PocketMine-Thread/

Thread
threadは、返り値の伴わないスレッド処理ができます。ですから、serverlistの情報送信のような一方的な作業に使うことができます。

        $job1 = new thread_ex1("Hello");
        $job1->start();

class thread_ex1 extends Thread
{
    public function _construct($data)
    {
        $this->data = $data;
    }
    public function run()
    {
        echo $this->data;
       Server::getInstance()->getLogger()->notice($this->data);// 動かない、無言だがエラーとなる
    }
}

最初の $job1 = new thread_ex1("Hello");
で、仕事を生成します。
()内には、引き渡したい変数をかけます。
(引き渡し先は、_construct($data)です。この関数の中に $this->data = $data; と定義してあげると、run内で利用できます。)
$job1->start(); で仕事実行です。
すると、_construct、runの関数の順に実行されます。
ただし、run内で、phpで書いた関数はスレッドクラス外から呼び出せないです。


AsyncTask
これは動作完了時に、任意の作業をさせることができます。ですから、webに接続するタイプのログインプラグインであっても、通信が完了した時にログインを完了させれば、他の人がラグを感じずに済むわけです。

$this->getServer()->getScheduler()->scheduleAsyncTask($job4 = new thread_ex3(Server::getInstance()));

class thread_ex3 extends AsyncTask
{
public function __construct($instance)
{
$this->instance =$instance;
}
public function onRun()
{

echo PHP_EOL."job3 1-2";
//$this->instance->getLogger()->notice("job3 1-1"); //動かない、無言だがエラーとなる
}
public function onCompletion(Server $server)
{
echo PHP_EOL."job3 2-2";
$server->getLogger()->notice("job3 2-1");
}
}

最初の、 $job4 = new thread_ex3(云々 の変数で、仕事を作成、scheduleAsyncTask で開始させています。
すると、_construct が実行、onRun が実行され、 onRunが完了すれば、onCompletionが実行されるでしょう。
onRun内では、外部の関数が実行できませんが、onCompletionでは、Serverの変数が渡されるので、$server を$this->getServer()として見なせば、pmmpが操作できます。

イントロの逆ってアウトロなんですね!
以上、マルチスレッドの方法について、まとめてみました。
サンプルプラグインを触れば、何ができるかよりわかると思います。
もともと、ある人の鯖の軽量化のためだけに考えたのですが、もうその人は鯖をやめてしまい、自分も開かないことをその人に進めたので、墓場(github)に埋もれていました。ですから、せっかくなので拾い上げ、記事にしました。
これで少しでも使う人が増えたらいいなと思います。今回はざっとしか書いてないですけど、反応を見て続編を書きたいです。

参考:

https://github.com/pmmp/PocketMine-MP/blob/master/src/pocketmine/scheduler/AsyncTask.php
https://github.com/organization/SpawningPool
 お世話になった、おぎわら、ありがと!
https://twitter.com/CostlierRain464

1 件のコメント:

  1. AsyncTaskについて

    onRun()内では別スレッド上で行いたい処理を記述し、onCompletion()内ではメインスレッド上で行いたい処理を記述できます

    なので、onRun()内で、メインスレッド上で動くServerの関数を呼び出すことはできません

    なお、スレッドを無駄に生成すると、メモリに負担がかかるので、なるべくAsyncTaskを継承したクラスを定義して、使うことが勧められます。

    返信削除

PocketMineの旧プラグインAPI対応方法

pmmp公式のプラグインAPIが変更となりました。 が、多くのプラグインは新APIに対応していません。 あえて新APIにプラグインを書き直す理由もわからないので、スクリプトを組みました。 Error: Declaration of DevTools\DevTools::...