Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

cron-like timing within perl script?

by n8ur (Acolyte)
on Feb 28, 2004 at 19:01 UTC ( [id://332507]=perlquestion: print w/replies, xml ) Need Help??

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

Hi all -- I am trying to design a perl script that triggers data collection and logging every X seconds. The problem is that the collection process (reading data from an external instrument via a GPIB port) takes an imprecise amount of time; on a 60-second cycle, I can estimate the time the instrument will take to within two or three seconds, but not more closely than that.

So something as simple as:

while (1) { get_data_taking_exactly_55_seconds; sleep(5); write_log_file; }

doesn't cut it; my log entries won't be properly aligned because the data collection function may take a bit more or less than 55 seconds.

What I want to do, I think, is along the lines of:

while (1) { set timer; get_data_taking_55_seconds_give_or_take_a_few; sleep_until_timer_says_60_seconds; write_log_file; }

It seems like using the alarm function to trigger the reading process on receipt of SIGALRM should let me do this but I haven't figured out how to make it work reliably; in particular, I can't figure out what kind of loop structure I need to keep the program alive.

I'd sure appreciate any help on how to implement a "sleep until alarm" capability in my program.

Thanks!

Replies are listed 'Best First'.
•Re: cron-like timing within perl script?
by merlyn (Sage) on Feb 28, 2004 at 19:45 UTC
Re: cron-like timing within perl script?
by flyingmoose (Priest) on Feb 28, 2004 at 19:38 UTC

    Yes, I think you want something like (warning, untested:)

    while ($looping) { # mark the time $t = time(); # do whatever you want here execute_my_periodic_operation_here(); # wait until the end of 60 seconds # but don't hammer the cpu .. the sleep keeps # from calling time() way too often while(time() < $t+60) { sleep(1); } }

    * note that the above example is not set to wait for even 60 second boundaries of t. I'm assuming you don't care. If clean minute boundaries are important, this needs to be implemented differently.

    Another non-wheel-reinventing option might be to look at POE. POE is fairly cool, but it tends to not fit in with normal programming idioms, so it may change the architecture of your program somewhat.

    Other monks may be able to suggest other CPAN modules that would be cleaner and more portable than the ALARM (or my version) and less heavyweight than POE. I'd be interested to hear what those were.

    Update: merlyn's code below is more efficient and his code sleeps to the next 60 second boundary... this is closer to what you want.

      Another non-wheel-reinventing option might be to look at PAR. PAR is fairly cool, but it tends to not fit in with normal programming idioms, so it may change the architecture of your program somewhat.
      That sentence makes a lot more sense if I replace PAR with POE. Perhaps you meant POE instead?

      -- Randal L. Schwartz, Perl hacker
      Be sure to read my standard disclaimer if this is a reply.

        Yep. Too many TLA's around here.
Re: cron-like timing within perl script?
by matija (Priest) on Feb 28, 2004 at 19:52 UTC
    You're very close to the right answer, and if I take your code, it would look like this:
    while (1) { next_time=time+60; get_data_taking_55_seconds_give_or_take_a_few; sleep next_time-time; write_log_file; }

    Note that you will still have a +/- 1 second drift, so the exact time of measurements would still drift.

    For higher accuracy, you pre-determine the times:

    next_time=time; while (1) { next_time=next_time+60; get_data_taking_55_seconds_give_or_take_a_few; sleep next_time-time; write_log_file; }
      This looks like the ticket... particularly if I use Time::HiRes to get subsecond time and sleep resolutions; that'll let me stay within my measurement tolerances.

      Thanks! This is a great resource!!!

      John

        You don't need Time::HiRes if you always sleep to a multiple of the 1-second system clock, which sleep(2) does. Since your requirement was an integer multiple of 1 second, that's the simplest. Now, if you wanted a task performed every 59.23 seconds, yes, Time::HiRes would help.

        -- Randal L. Schwartz, Perl hacker
        Be sure to read my standard disclaimer if this is a reply.

        Sorry... didn't realize I wasn't logged in when I left that. Thanks again!

        John

Re: cron-like timing within perl script?
by Anonymous Monk on Feb 29, 2004 at 23:06 UTC

    Funnily enough, as I'm reading this page the aphorism under the banner is "Keep It Simple, Stupid" (no offense, it really is what it says)!

    If you want the script to do something once every sixty seconds, why not simply run it under cron (or atd or windows scheduler or whatever) every minute?

    You wouldn't have to worry so much about memory leaks or monitoring for your process getting inadvertantly killed, etc either. Am I missing something?

Re: cron-like timing within perl script?
by fuzzycow (Sexton) on Mar 01, 2004 at 13:09 UTC
    There are a number of cron-like perl modules on CPAN. I worked with Schedule::Cron, and it performed rather nicely. If you don't want your jobs to fork you may want to try Schedule::Cron::Nofork (haven't checked this one yet)
Re: cron-like timing within perl script?
by mce (Curate) on Mar 02, 2004 at 11:11 UTC
    Hi,

    Why not fool around with alarm and its signal handler $SIG{ALRM}?

    I don't have time to make such a script, but this might help you.


    ---------------------------
    Dr. Mark Ceulemans
    Senior Consultant
    BMC, Belgium
Re: cron-like timing within perl script?
by Tomte (Priest) on Mar 02, 2004 at 11:21 UTC

    Update: Gee, I should read the whole thread more thoroughly before answering, completly overlooked fuzzycow's recommending the same module...

    I feel obliged to mention Schedule::Cron, which might do more than necessary, but seems appropriate to me.

    regards,
    tomte


    Hlade's Law:

    If you have a difficult task, give it to a lazy person --
    they will find an easier way to do it.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://332507]
Approved by flyingmoose
Front-paged by Plankton
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (5)
As of 2024-04-23 21:27 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found