Команды Laravel, Pthreads и Закрытие

Необходимо выполнить конкретный процесс несколькими потоками. Я узнал о расширении для php - pthreads.

Например, простой сценарий вне Laravel работает отлично, и мне понравились результаты. Я решил переехать в Ларавел и столкнулся с проблемой. Конечно я искал в гугле, нашел несколько вопросов по stackru, где ответил автор расширения. Но мне не помогли его ответы, поэтому я прошу вас помочь мне.

Ответ на вопрос расширения автора.

Есть класс App\Commands\QuestionsParserCommand. Внутри я создал экземпляр класса App\My\Questions\QuestionsParser и вызвал метод init(). Тогда код метода init():

// Create a pool
$pool = new Pool($this->threads, ParserWorkers::class);

// Create a thread class
$thread = new class extends Threaded
{
  public function run()
  {
    // The class will receive data from a provider
    // that will be shared between threads through ParserWorkers.
    // It will work with the API and store the data in the database.
    // The need to work with the threads,
    // because the data for processing an incredible amount.

    echo '+';
  }
};

// Start a threads
for ($i = 0; $i < $this->threads; $i++) {
  $pool->submit($thread);
}

$pool->shutdown();

Класс ParserWorkers наследуется от Worker и все же имеет пустой метод run().

В результате я запускаю скрипт и получаю сообщение в журнале php:

[13-Oct-2016 11:27:35 Europe/Moscow] PHP Fatal error:  Uncaught Exception: Serialization of 'Closure' is not allowed in [no active file]:0
Stack trace:
#0 {main}
  thrown in [no active file] on line 0

Информация: Laravel 5.2.43, php 7.0.8, Windows

Спасибо вам всем!

1 ответ

Сначала вы можете ознакомиться со стратегией автора библиотеки: https://github.com/krakjoe/pthreads-autoloading-composer

Используемая здесь стратегия гарантирует, что каждый поток (Worker) получает локальную копию потока структуры или того, что загружается, но не нарушает возможности объектов, которые происходят от pthreads.


Во-вторых, чтобы начать работу с функциями laravel (такими как поставщики услуг, фасады, помощники и т. Д.), Вам нужно инициализировать laravel.

Я посмотрел, как инициализировать приложение в файле tests/CreatesApplication.php. Код ниже показывает, как это сделать для Laravel 5.7 с php 7.2.

Важно: укажите правильный путь к autoload.php и app.php относительно расположения файла Autoloader.php.

namespace App\Console\Commands;

use Worker;

use Illuminate\Contracts\Console\Kernel;

class Autoloader extends Worker
{
    public function run()
    {
        require __DIR__. '/../../../vendor/autoload.php';
        $app = require __DIR__.'/../../../bootstrap/app.php';
        $app->make(Kernel::class)->bootstrap();
    }

    public function start($options = PTHREADS_INHERIT_ALL)
    {
        return parent::start(PTHREADS_INHERIT_INI);
    }

}
namespace App\Console\Commands;

use Exception;
use Threaded;

class OperatorThread extends Threaded
{
    /**
     * @var OperatorThreaded
     */
    private $operator;
    private $error;

    public function __construct(OperatorThreaded $operator)
    {
        $this->operator = $operator;
    }

    public function run()
    {
        try {
            $this->operator->handle();
        } catch (Exception $exception) {
            $this->error = (string) $exception;
        }
    }

    public function getError() {
        return $this->error;
    }

}
namespace App\Console\Commands;

class OperatorThreaded
{
    private $i;

    public function __construct($i)
    {
        $this->i = $i;
    }

    public function handle()
    {
        sleep(rand(1,3));
        if (app()->isBooted()) {
            echo $this->i . PHP_EOL;
        }
    }

}

Теперь вы можете использовать Laravel с pthreads:

namespace App\Console\Commands;

use Pool;

use Illuminate\Console\Command;

class Test extends Command
{
    protected $description = 'test';
    protected $signature = 'test';

    public function handle()
    {
        $operators = [];
        for ($i=0; $i<5; $i++) {
            $operators[] = new OperatorThreaded($i);
        }

        $pool = new Pool(count($operators), Autoloader::class);
        foreach ($operators as $operator) {
            $thread = new OperatorThread($operator);
            $pool->submit($thread);
        }

        while ($pool->collect());
        $pool->shutdown();
    }
}
$ php artisan test
1
2
4
0
3
foreach ($this->pool as $w) {
   $w->start(PTHREADS_INHERIT_ALL ^ PTHREADS_INHERIT_CLASSES);
}
Другие вопросы по тегам