Как сделать неблокирующее чтение из канала в Perl? - PullRequest
2 голосов
/ 23 сентября 2010

У меня есть программа, которая вызывает другую программу и обрабатывает вывод дочернего элемента, то есть:

my $pid = open($handle, "$commandPath $options |");

Теперь я попробовал несколько различных способов чтения из дескриптора без блокировки с небольшим успехом или безуспешно..

Я нашел похожие вопросы:

Но онистрадают от проблем:

  • ioctl постоянно вылетает perl
  • sysread блоков на 0 байтов (обычное явление)

I'mне уверен, как идти о решении этой проблемы.

1 Ответ

4 голосов
/ 23 сентября 2010

Трубы не так функциональны в Windows, как в системах Unix-y. Вы не можете использовать 4-аргумент select для них, и емкость по умолчанию минимальна.

Лучше попробовать обходной путь на основе сокета или файла.

$pid = fork();
if (defined($pid) && $pid == 0) {
    exit system("$commandPath $options > $someTemporaryFile");
}
open($handle, "<$someTemporaryFile");

Теперь у вас есть еще пара банок червей - периодически запускайте waitpid, чтобы проверить, когда фоновый процесс прекратил создавать выходные данные, вызывая seek $handle,0,1, чтобы очистить условие eof после чтения из $handle очистка временного файла, но он работает.

Я написал модуль Forks::Super для решения подобных проблем (и многих других). Для этой проблемы вы бы использовали его как

use Forks::Super;
my $pid = fork { cmd => "$commandPath $options", child_fh => "out" };
my $job = Forks::Super::Job::get($pid);
while (!$job->is_complete) {
    @someInputToProcess = $job->read_stdout();
    ... process input ...
    ... optional sleep here so you don't consume CPU waiting for input ...
}
waitpid $pid, 0;
@theLastInputToProcess = $job->read_stdout();
...