Timeouts in Perl

Timeouts are important for programs that connect to external resources or that otherwise need to bound execution time. Implementing timeouts in Perl is possible using the Time::HiRes module and the select function.

use strict;
use warnings;
use Time::HiRes qw(time sleep);
use IO::Select;

sub main {
    # For our example, suppose we're executing an external
    # call that returns its result after 2s. We'll use a pipe
    # to simulate this behavior.
    my ($reader, $writer);
    pipe($reader, $writer);
    my $pid = fork();
    
    if ($pid == 0) {  # Child process
        close $reader;
        sleep(2);
        print $writer "result 1";
        exit;
    }
    
    close $writer;

    # Here's the select implementing a timeout.
    # We create an IO::Select object and add our reader to it.
    my $select = IO::Select->new($reader);
    my $timeout = 1;  # 1 second timeout
    
    if (my @ready = $select->can_read($timeout)) {
        my $res = <$reader>;
        chomp $res;
        print "$res\n";
    } else {
        print "timeout 1\n";
    }

    # If we allow a longer timeout of 3s, then the read
    # from the pipe will succeed and we'll print the result.
    pipe(my $reader2, my $writer2);
    my $pid2 = fork();
    
    if ($pid2 == 0) {  # Child process
        close $reader2;
        sleep(2);
        print $writer2 "result 2";
        exit;
    }
    
    close $writer2;

    $select = IO::Select->new($reader2);
    $timeout = 3;  # 3 second timeout
    
    if (my @ready = $select->can_read($timeout)) {
        my $res = <$reader2>;
        chomp $res;
        print "$res\n";
    } else {
        print "timeout 2\n";
    }
}

main();

Running this program shows the first operation timing out and the second succeeding.

$ perl timeouts.pl
timeout 1
result 2

In this Perl version:

  1. We use the Time::HiRes module for high-resolution time functions.
  2. Instead of channels, we use pipes to communicate between parent and child processes.
  3. We use fork() to create child processes that simulate the delay.
  4. The IO::Select module is used to implement the timeout functionality, which is similar to Go’s select statement.
  5. The can_read() method of IO::Select is used with a timeout value to wait for data or timeout.

This Perl implementation captures the essence of the original Go program, demonstrating how to handle timeouts when waiting for results from operations that might take too long.