Reputation: 201
It may be a simple question for a perl expert -
I am trying to run a script which should logically do this>
Main
{
While (true)
Call Sub A
Call Sub B
Call Sub C
}
Sub A
{
Go execute a method A for whatever it needs to do ---
before next time method A runs it need to wait atleast 60 seconds but i still want to call method B in these 60 seconds.
}
Sub B
{
Go execute a method B for whatever it needs to do ---
before next time method b runs it need to wait atleast 60 seconds but i still want to call method C in these 60 seconds in mean time.
}
Sub C
{
Go execute a method C for whatever it needs to do ---
before next time method C runs it need to wait atleast 60 seconds at this moment control should be back in Main and wait for first 60 seconds of A to expire so that Sub A can be called
}
My question: Q: what is best and optimized way can i do this -?
Q: If i put sleep 60 in each sub then next sub will not be called even till 60 seconds expire and it will delay overall processing.
Q: I want 3 subs called every 60 seconds in a sequential order
Q Lastly if i need to call 2 subs in every 60 seconds and last sub every hour - how do i do it?
Comment - my thought was to take UTC as a variable and store it in a variable and keep checking time if time expires than call individual subs but not sure if it optimum way of running code.
Upvotes: 1
Views: 902
Reputation: 50667
Using Amon idea, but with sleeping logic outside functions,
sub get_sleeper {
my ($sleep_duration) = @_;
my $last_execution = 0;
return sub {
my $remaining = $last_execution + $sleep_duration - time();
sleep $remaining if $remaining >0;
$last_execution = time();
};
}
my ($sleepA, $sleepB, $sleepC) = map get_sleeper(60), 1..3;
while (1) {
$sleepA->(); SubA();
$sleepB->(); SubB();
$sleepC->(); SubC();
}
Upvotes: 1
Reputation: 1404
Both answers are good but a sort of middle way would be: (stolen from the answer by amon)
use feature 'state';
my $sleep_duration = 60; # seconds
sub foo {
state $last_execution = 0;
my $remaining = $last_execution + $sleep_duration - time;
if ($remaining > 0)
{
return "Waiting"; # Make sure main checks for this to know whether the sub ran.
}
...; # normal processing for this sub
}
This will allow you to run the next sub while this one wait without needing more than one thread. But of course, it means that this sub will run only after the other two had their chance. This means you mix up the order and depending on subs, take longer than 60 seconds till the next call.
Upvotes: 0
Reputation: 40573
You probably want to use threads. The following snippet might give you a starting point. Since you have four Qs instead of one, I won't go into detail for each of them.
#!/usr/bin/perl
use warnings;
use strict;
use threads;
my @t = (
threads->create(\&A),
threads->create(\&B),
threads->create(\&C)
);
$t[0] -> join();
$t[1] -> join();
$t[2] -> join();
sub A {
for my $i (1 .. 10) {
print "A $i\n";
sleep 60;
}
}
sub B {
for my $i (1 .. 20) {
print "B $i\n";
sleep 60;
}
}
sub C {
for my $i (1 .. 3) {
print "C $i\n";
sleep 60;
}
}
Upvotes: 1
Reputation: 57640
Inside the subroutine record the time when it last ran, then wait if necessary on the next execution:
use feature 'state';
my $sleep_duration = 60; # seconds
sub foo {
state $last_execution = 0;
my $remaining = $last_execution + $sleep_duration - time;
sleep $remaining if $remaining > 0;
$last_execution = time;
...; # normal processing for this sub
}
Upvotes: 3