2016-08-10 1 views
1

Мне нужно отправить некоторые изображения через tesseract, и для экономии времени я хочу запустить tesseract параллельно с до 6 экземплярами.Запуск PHP с многопоточным (tesseract)

Я посмотрел на этот вопрос, но не могу действительно понять, как писать код

How can one use multi threading in PHP applications

Все изображения выбираются из базы данных, а результаты записываются обратно к конкретной строке в базы данных вместе с остальной частью информации, связанной с изображением

Не могли бы вы обратиться к примеру или могли бы написать быстрый пример о том, как выполнить эту работу?

Когда процесс завершен, необходимо запустить новый, так что одновременно будет работать до 6 процессов?

обновление

class Command { 
    private $descriptorspec; 

    private $output = ''; 

    public function __construct(){ 
     $this->descriptorspec = [ 
      0 => ['pipe', 'r'], // stdin 
      1 => ['pipe', 'w'], // stdout 
      2 => ['pipe', 'w'], // stderr 
     ]; 
    } 

    public function output(): string{ 
     return $this->output; 
    } 

    public function exec(string $syntax): string{ 
     $process = proc_open($syntax, $this->descriptorspec, $pipes); 

     $this->output = stream_get_contents($pipes[1]); 
     fclose($pipes[1]); 

     $stderr = stream_get_contents($pipes[2]); 
     fclose($pipes[2]); 

     proc_close($process); 

     return $stderr; 
    } 
} 

$Cmd = new Command; 
$Cmd->exec('tesseract ...'); 
+1

Что вы повторно ally want - это другой сервер, на котором вы также разгружаете эти процессы. Альтернативно, если вы используете Laravel, у них есть отличный модуль Run Queue, позволяющий параллельно выполнять параллельные задания. – Alex

ответ

0

не делают этого. PHP имеет очень дерьмовую поддержку многопоточности. вместо этого используйте многопроцессорную обработку. использование proc_open & co. - http://php.net/manual/en/function.proc-open.php

+0

Вы не правы. Ядро php отлично работает при многопоточности. Но я согласен, что это не всегда необходимо. –

+0

@MaximTkach нет нет. цитируя несколько предупреждений: 'Когда выполняются функции print_r, var_dump и других объектов, они не включают защиту от рекурсии.' - 'Любые объекты, предназначенные для использования в многопоточных частях вашего приложения, должны расширять Threaded.' (без объяснения причин) - 'при запуске контекста класс, чьи статические члены включают информацию о соединении для сервера базы данных и само соединение, будет иметь только скопированную информацию о соединении, а не соединение ' – hanshenrik

+0

' Ресурсы: расширения и функциональность которые определяют ресурсы в PHP, совершенно не готовы к такой среде; Однако pthreads позволяет распределять ресурсы между контекстами, однако для большинства типов ресурсов его следует считать небезопасным. Крайняя осторожность и осторожность должны использоваться при совместном использовании ресурсов между контекстами. – hanshenrik

0

Вам не нужно использовать многопоточность. Чтобы запустить 6 рабочих, без необходимости синхронизации с родительским процессом, вы можете использовать proc_open

Многопоточность выполняется быстрее, занимает меньше ресурсов (для этого нет отдельного пространства имён), и вы можете запускать их в 4 раза больше, чем вилки, но многопоточность требует создания PHP с не-ZTS (некоторые расширения не работают с не-ZTS) и требует чего-то, что вы понимаете для модели pthread.

Для exampe:

Мы создаем 6 работника с proc_open и базовый процесс слушать умереть Чайлдс (я использую свою обертку, работа с Ev Li или событий Lib или без них) (child-processes), может быть, вам нравится обертка reactphp (child-processes)

$child = new ChildProcesses(); 
    $child->add('<system command>'); 
    $child->add('<system command>'); 
    $child->add('<system command>'); 
    $child->add('<system command>'); 
    $child->add('<system command>'); 
    $fails = $child->check(null, function(ChildProcess $process) { 
     echo 'Error with chld process'; 
    }); 

Или использовать потоковой чтения официальный documentatin. Ваша потребность перекомпилировать PHP в не-ZTS и установить расширение pthread. Для вашей проблемы, я хотел бы использовать бассейн

Вы должны смотреть на первый пример на этой странице Pool pthreads

Update:

Если вам нужно иметь все время - шесть рабочих. Вам нужно создать шесть слушателей. И связь между процессами использует zmq или rabbitmq, gearman или другую другую очередь. Ваши процессы никогда не умрут, а падший поднимется надзирателем.

Например:

$loop = Factory::create(); 
$context = new Context($loop)); 
$context->getSocket(\ZMQ::SOCKET_SUB); 
$context->connect($host); 
$context->subscribe('you_queue'); 
$context->on('messages', function($messages){ 
    // get specific data and run operation 
}); 
$loop->run(); 

Будьте осторожны, zmq не совсем очередь.

  1. Это не сохраняет сообщения
  2. реагировать/zmq использует EventLib, поэтому на самом деле мой пример будет асинхронным.

Вы должны использовать Gearman или RabbitMQ - там есть идеальные функциональные возможности для вашей задачи


С уважением Максим

+0

Когда процесс будет завершен, как начать новый, так что всегда будет одновременно работать до 6 процессов? – clarkk

+0

Я решил, что тебе нужно умереть и умереть. Если требуется всегда шесть рабочих - каждый рабочий должен быть очереди слушателей. Я рекомендую использовать ZMQ (реакция/zmq) или Redis для прослушивания новых задач.) –

0

Я написал пример (основание на child-processes). Это должно решить вашу проблему:

Это parent.php:

$child = new ChildProcesses(); 
$child->addProcessInstance(new \TkachInc\ChildProcesses\ChildProcess('php worker.php -w1')); 
$child->addProcessInstance(new \TkachInc\ChildProcesses\ChildProcess('php worker.php -w2')); 
$child->addProcessInstance(new \TkachInc\ChildProcesses\ChildProcess('php worker.php -w3')); 
$child->addProcessInstance(new \TkachInc\ChildProcesses\ChildProcess('php worker.php -w4')); 
$child->addProcessInstance(new \TkachInc\ChildProcesses\ChildProcess('php worker.php -w5')); 
$child->addProcessInstance(new \TkachInc\ChildProcesses\ChildProcess('php worker.php -w6')); 
$child->daemon(); 

И ваш worker.php (я добавил пример вывода, вам нужно удалить его):

$options = getopt("w:"); 
if(isset($options['w'])) 
{ 
    echo $options['w'].PHP_EOL; 

    switch ($options['w']) 
    { 
     case "1": 
      sleep(5); 
      break; 
     case "2": 
      sleep(5); 
      break; 
     case "3": 
      sleep(7); 
      break; 
     case "4": 
      sleep(5); 
      break; 
     case "5": 
      sleep(7); 
      break; 
     case "6": 
      sleep(5); 
      break; 
    } 
} 

// your logic to receive from database and write to database 

С уважением Максим