DBX has asked for the wisdom of the Perl Monks concerning the following question:
I wrote a system which uses Storable::freeze() to serialize a data structure. It then uses IPC::Open2 and IO::Handle to spawn multiple child processes and write to them, reading back a status from each one.
When this runs, the children are causing huge CPU load (according to top), even when nothing is being read. I can't figure out why, probably due to my inexperience with IPC. I have RTFM'ed just about every IPC document I could get my hands on. There are multiple parents running at any given time and each parent will spawn any number of children. Right now, I'm experimenting with 10 children per parent. Some code for your review is below.
My question is: Is there something I'm missing in this code that would cause the CPUs to churn even when simply selecting and reading? Or is there something else I'm just not seeing? Snippets from the parent:and later in the code...my ($readHandle, $writeHandle) = (IO::Handle->new, IO::Handle->new +); my $pid = open2($readHandle, $writeHandle, @command); $readHandle->autoflush(1); $readHandle->blocking(0); $writeHandle->autoflush(1); $writeHandle->blocking(0);
The children that are spawned have a method to read the data from the parent and process it (modified a bit to remove business logic):## $messageForProcessing is a data structure stored as a hash refe +rence my $frozenMessage = freeze($messageForProcessing); print $writeHandle $frozenMessage . qq|\n| . $this->_messageDelimi +ter();
sub processMessages { my ($this) = @_; my $endTime = time + $ENV{'MAX_LIFETIME'}; select STDOUT; $|++; # make unbuffered my $select = IO::Select->new(); $select->add(\*STDIN); my $messageDelimiter = $this->_messageDelimiter(); my $delimiterMatch = qr{\n$messageDelimiter$}; my $frozenMessage; my $messageToProcess = {}; my $stopNow = 0; while(time < $endTime) { my $offset; my ($handle) = $select->can_read(5); my $previousRead; while( ($handle) && (my $bytes = $handle->sysread($frozenMessage, 8192, $offse +t)) ) { $offset += $bytes; ## Because Storable may put newlines in the frozen object, + ## delimit messages: my $searchableText = $previousRead . $frozenMessage; if($searchableText =~ /$delimiterMatch/) { $frozenMessage =~ s/$delimiterMatch//; $messageToProcess = thaw($frozenMessage); } $previousRead = $frozenMessage; if(%$messageToProcess) { ### DO MESSAGE PROCESSING HERE ## my $outputMessage; if($processor->hasErrors()) { my $errors = $processor->getErrors(); $outputMessage = qq|$$ ERROR $errors->[0]\n|; } else { my $messageID = $processor->lastMessageID(); $outputMessage = qq|$$ SUCCESS $messageID\n|; } ## Write status back to the parent print STDOUT $outputMessage; $offset = 0; undef($frozenMessage); undef($previousRead); undef(%$messageToProcess); } } } }
Process 22515 attached - interrupt to quit select(8, [0], NULL, NULL, {5, 0}) = 1 (in [0], left {5, 0}) read(0, "", 8192) = 0 select(8, [0], NULL, NULL, {5, 0}) = 1 (in [0], left {5, 0}) read(0, "", 8192) = 0 select(8, [0], NULL, NULL, {5, 0}) = 1 (in [0], left {5, 0}) read(0, "", 8192) = 0 select(8, [0], NULL, NULL, {5, 0}) = 1 (in [0], left {5, 0}) read(0, "", 8192) = 0 select(8, [0], NULL, NULL, {5, 0}) = 1 (in [0], left {5, 0}) read(0, "", 8192) = 0 select(8, [0], NULL, NULL, {5, 0}) = 1 (in [0], left {5, 0}) read(0, "", 8192) = 0 select(8, [0], NULL, NULL, {5, 0}) = 1 (in [0], left {5, 0}) read(0, "", 8192) = 0 select(8, [0], NULL, NULL, {5, 0}) = 1 (in [0], left {5, 0}) read(0, "", 8192) = 0
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Performance and CPU load: sysread, IO::Select and/or Storable::thaw
by jethro (Monsignor) on Jun 28, 2010 at 16:17 UTC | |
by DBX (Pilgrim) on Jun 28, 2010 at 22:48 UTC | |
by jethro (Monsignor) on Jun 29, 2010 at 18:21 UTC | |
by DBX (Pilgrim) on Jun 29, 2010 at 19:42 UTC | |
by jethro (Monsignor) on Jun 30, 2010 at 09:47 UTC | |
|