In Perl 5, how to queue a process/application after it reaches a maximum limit

夙愿已清 提交于 2019-12-10 11:45:46

问题


I have a program that is being symlinked to multiple directories e.g.

/main/foo.pl
/run1/foo.pl -> /main/foo.pl
/run2/foo.pl -> /main/foo.pl
/run3/foo.pl -> /main/foo.pl
/run4/foo.pl -> /main/foo.pl

They're being run as cron jobs, hence I have the following entries in the crontab:

*/2 * * * * /run1/foo.pl
*/2 * * * * /run2/foo.pl
*/2 * * * * /run3/foo.pl
*/2 * * * * /run4/foo.pl

A snippet of foo.pl is as below:

use Fcntl qw(:flock);
use autodie qw(:all);
open my $self, '>', "$FindBin::Bin/lockme";
flock( $self, LOCK_EX|LOCK_NB )
    or die "Cannot acquire lock, already running!";

{
    my $long_proc = Process->new();
    $long_proc->run();
}        

You get the idea, each of the cron process can only run once because there is a lock semaphore check. But run1, run2, run3, and run4 can run simultaneously.

Now what I need is that I want to limit the number of process to maximum of four. If someone adds another cron processes like:

New symlinks:

/run5/foo.pl -> /main/foo.pl
/run6/foo.pl -> /main/foo.pl

Additional crontab:

*/5 * * * * /run5/foo.pl
* * * * * /run6/foo.pl

Both run5 and run6 need to be queued whenever run1, run2, run3, and run4 are all still running. Thus at any given time there will be only 4 processes run.

How can I achieve that? Is there any CPAN module that handles it?

Thanks!


回答1:


You have a few general approaches:

Quick and Dirty

Have a directory with N lockfiles, and have each process try to lock each file in turn, sleeping a bit.

Caveat: It's a busy loop, yes, but it might be good enough.

Daemonic Redesign

Turn foo.pl into a local socket-listening daemon, as it is easy for a parent process to manage concurrency of its children. Turn your cron jobs into blocking requests for the daemon to so something. (See, e.g., Parallel::ForkManager).

Caveat: You'll have to carefully re-implement setuid/privilege changing code if you were using cron to run foo.pl as multiple different users.

Interprocess Semaphores, SysV

IPC::Semaphore is a somewhat more convenient interface to the SysV semget family of functions in perlfunc, and the SEM_UNDO flag means that the unexpected process death of one of your workers won't "waste" a semaphore increment.

Caveat: You'll likely need to create and initialize the SysV semaphore in a separate process, distinct from foo.pl, since you cannot create and initialize a SysV semaphore in an atomic operation.

Interprocess Semaphores, POSIXly

POSIX::RT::Semaphore also supports interprocess semaphores. The API is simpler than SysV, and semaphores can be exclusively created and initialized to a value in an atomic syscall.

This is probably what I'd use.




回答2:


Please see comment from @tsee in @pilcrow answer above. Steffen Muller's IPC::ConcurrencyLimit can control the number of concurrenct processes on cooperative multi processing nicely.



来源:https://stackoverflow.com/questions/14639181/in-perl-5-how-to-queue-a-process-application-after-it-reaches-a-maximum-limit

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!