Acme-Parataxis
view release on metacpan or search on metacpan
lib/Acme/Parataxis.pod view on Meta::CPAN
=head2 C<set_preempt_threshold( $val )>
Sets the number of C<maybe_yield> increments before a forced yield occurs. Default is 0 (preemption disabled).
=head1 Class Methods
=head2 C<tid( )>
Returns the unique OS Thread ID of the main interpreter thread.
=head2 C<current_fid( )>
Returns the unique numeric ID of the currently executing fiber, or -1 if called from the "root" (main) context.
=head2 C<root( )>
Returns a proxy object representing the initial execution context. This is useful for C<transfer( )>ing control back to
the main thread from a symmetric coroutine.
=head1 Acme::Parataxis OBJECT METHODS
=head2 C<fid( )>
Returns the unique numeric ID of the fiber object.
=head2 C<is_done( )>
Returns true if the fiber has finished execution (either by returning or dying). Once a fiber is done, its internal ID
is released and it can no longer be called.
=head1 Acme::Parataxis::Future OBJECT METHODS
=head2 C<await( )>
Suspends the current fiber until the future is ready. Returns the result or B<dies> if the task encountered an error.
=head2 C<is_ready( )>
Returns true if the task associated with the future has completed.
=head2 C<result( )>
Returns the task result immediately. Croaks if the future is not yet ready.
=head1 INTEGRATING SYNCHRONOUS MODULES
To use synchronous modules (like C<HTTP::Tiny>) in a non-blocking way, you can subclass their handle or transport
methods and use a C<while> loop combined with C<yield('WAITING')>. This ensures the fiber yields control until the
underlying I/O is ready.
# Example: A cooperative HTTP::Tiny subclass
{
package My::HTTP;
use parent 'HTTP::Tiny';
sub _open_handle {
my ($self, $request, $scheme, $host, $port, $peer) = @_;
return My::HTTP::Handle->new(
timeout => $self->{timeout},
keep_alive => $self->{keep_alive},
keep_alive_timeout => $self->{keep_alive_timeout}
)->connect($scheme, $host, $port, $peer);
}
sub request {
my ($self, $method, $url, $args) = @_;
my %new_args = %{ $args // {} };
my $orig_cb = $new_args{data_callback};
my $content = '';
$new_args{data_callback} = sub {
my ($data, $response) = @_;
if ($orig_cb) { return $orig_cb->($data, $response) }
$content .= $data;
return 1;
};
my $res = $self->SUPER::request($method, $url, \%new_args);
$res->{content} = $content unless $orig_cb;
return $res;
}
}
{
package My::HTTP::Handle;
use parent -norequire, 'HTTP::Tiny::Handle';
use Time::HiRes qw[time];
sub _do_timeout {
my ($self, $type, $timeout) = @_;
$timeout //= $self->{timeout} // 60;
my $start = time;
while (1) {
# Check for readiness NOW (0 timeout)
return 1 if $self->SUPER::_do_timeout($type, 0);
# Check for overall timeout
my $elapsed = time - $start;
return 0 if $elapsed > $timeout;
# Suspend fiber and wait for background I/O check
my $wait = ($timeout - $elapsed) > 0.5 ? 0.5 : ($timeout - $elapsed);
if ($type eq 'read') {
Acme::Parataxis->await_read($self->{fh}, int($wait * 1000));
} else {
Acme::Parataxis->await_write($self->{fh}, int($wait * 1000));
}
}
}
}
=head1 EXAMPLES
=head2 Cooperative Parallelism
This example demonstrates how to perform multiple HTTP requests concurrently on a single interpretation thread.
use Acme::Parataxis;
# ... (See My::HTTP implementation in INTEGRATING SYNCHRONOUS MODULES) ...
Acme::Parataxis::run(sub {
my $http = My::HTTP->new(verify_SSL => 0);
my @urls = qw[http://example.com http://perl.org];
# Spawn tasks for each URL
my @futures = map {
my $url = $_;
Acme::Parataxis->spawn(sub { $http->get($url)->{status} })
( run in 0.677 second using v1.01-cache-2.11-cpan-df04353d9ac )