ombibulous has asked for the wisdom of the Perl Monks concerning the following question:

Hello,

I'm playing with a toy POE program that implements two sessions connected by a pipe that should simply cat an inupt file. Something like this:

+- read side of pipe / ---------- ---------- STDIN --> | reader | -pipe-> | writer | --> STDOUT ---------- ---------- \ +- write side of pipe

I started by using rcaputo's example that he posted here at perlmonks.org/?node_id=949005 and came up with this non-working code:

use strict; use warnings; use IO::Pipely qw(pipely); use POE qw(Wheel::ReadWrite); my ($read_pipe, $write_pipe) = pipely(); # reader sends output to the write pipe my $reader = POE::Session->create( args => [ $write_pipe ], inline_states => { _start => sub { $_[HEAP]->{wheel} = POE::Wheel::ReadWrite->new( InputHandle => \*STDIN, OutputHandle => $_[ARG0], InputEvent => 'got_input', ErrorEvent => 'got_input_error', ); }, got_input => \&handle_input, got_input_error => \&handle_input_error, process_next_input => \&process_next_input, } ); # writer reads input from the read pipe my $writer = POE::Session->create( args => [$read_pipe], inline_states => { _start => sub { $_[HEAP]->{wheel} = POE::Wheel::ReadWrite->new( InputHandle => $_[ARG0], OutputHandle => \*STDOUT, InputEvent => 'got_input', ErrorEvent => 'got_input_error', ); }, got_input => \&handle_input, got_input_error => \&handle_input_error, process_next_input => \&process_next_input, } ); POE::Kernel->run(); exit; sub handle_input { my ( $kernel, $heap, $input ) = @_[KERNEL, HEAP, ARG0]; print $heap->{wheel}->put( $input ); $heap->{wheel}->flush(); $heap->{wheel}->pause_input(); $kernel->yield( 'process_next_input' ); } sub handle_input_error { my ($kernel, $heap) = @_[KERNEL, HEAP]; $kernel->yield( 'process_next_input' ); delete $heap->{wheel}; } sub process_next_input { my ($kernel, $heap) = @_[KERNEL, HEAP]; $heap->{wheel}->resume_input() if $heap->{wheel}; }

On my Mac using Perl 5.20 I get this as the output when I feed the program a three line CSV file:

ombibulous> perl cat.pl < test.csv 00001,2,3,4 0a,b,c,d 0foo,bar,baz ^C ombibulous>

The ^C is me yanking the rope on my hung program. The lines should not begin with '0's, I don't know how they are creeping in.

I thought (hoped) that after the $reader's handle_input() subroutine does a put(), pauses_input(), and yield(), then POE would see that there is an input for the $writer session and call its input handler. WRONG! I'm not getting how one session cedes processing to another session. I've seen the examples using posts() but I'm trying pipes instead. Can anyone tell me what I'm doing wrong?

Eventually I'd like to build up a chain of sessions, connected by pipes, where each session does a particular transformation on input data; e.g., reader -> parser -> writer. I've already done this with a single process, parsing and writing within a read loop, and subprocesses, forked process for each step. I'd like to see how it works using POE. Is POE::Wheel::ReadWrite the best package to use if I'm going to use a single process?

Thanks for any help, insights, and/or solutions.

Replies are listed 'Best First'.
Re: Problem using POE::Wheel::ReadWrite with pipes.
by haukex (Archbishop) on Sep 24, 2016 at 11:38 UTC

    Hi ombibulous,

    The lines should not begin with '0's, I don't know how they are creeping in.

    I can answer that part of your question: It's the print $heap->{wheel}->put( $input );, which is printing the return value of put, which is 0.

    Although I've worked with POE a little bit, I haven't come across your use case. And looking around in the incredibly useful POE Cookbook haven't shown me any use cases that resemble yours, so not being a POE expert I can't offer more at the moment.

    Regards,
    -- Hauke D

Re: Problem using POE::Wheel::ReadWrite with pipes.
by rcaputo (Chaplain) on Sep 25, 2016 at 05:47 UTC

    That's not a very efficient way to perform the immediate task at hand, but it's a decent learning exercise.

    The reason your program isn't exiting is that the $writer session is still active. You got an EOF on STDIN, which shut down the $reader, but $write_pipe is still open and waiting for data.

    If you close $write_pipe in handle_input_error() it will cascade the EOF from $reader to $writer, at which point the $writer session will end, and the program will exit.

Re: Problem using POE::Wheel::ReadWrite with pipes.
by ombibulous (Initiate) on Sep 26, 2016 at 10:56 UTC

    Thank you for the replies. I was going to use the "toy" program to benchmark the idea. I had my doubts that using pipes within a single process could be faster than my read/write loop, but this is Perl and stranger things are known to be true.

    I did learn more about POE. In a previous application I managed to get POE::Wheel::Run working without really understanding what was going on. I now have a better feel for how POE works and what is possible using it.

    Thanks again!