gpt4 book ai didi

perl - Perl用子守护程序守护

转载 作者:行者123 更新时间:2023-12-04 13:32:03 27 4
gpt4 key购买 nike

我必须在代码中使用守护程序。我需要一个控制守护程序,该守护程序不断检查数据库中的任务并监督子守护程序。控制守护程序必须将任务分配给子守护程序,控制任务,如果其中一个子进程死亡,则创建新的子进程,等等。子守护程序检查数据库中的子任务(通过PID)。为此,我应该如何实现守护程序?

最佳答案

守护进程只是“长时间运行的后台进程”的代名词。因此,答案是“取决于”。 Perl有两种​​主要的进行多处理的方式:

线程

您可以将子例程作为线程与主程序代码并行运行。 (然后可能只监视线程状态)。

创建线程的开销较高,但更适合“共享内存”样式的多处理,例如当您来回传递大量数据时。有几个库使在线程之间传递信息非常简单。我个人非常喜欢 Thread::Queue Thread::Semaphore Storable

特别是-Storable具有freezethaw,可让您在队列中四处移动复杂的数据结构(例如,对象/哈希),这非常有用。

基本线程示例:

#!/usr/bin/perl

use strict;
use warnings;

use threads;

use Thread::Queue;

my $nthreads = 5;

my $process_q = Thread::Queue->new();
my $failed_q = Thread::Queue->new();

#this is a subroutine, but that runs 'as a thread'.
#when it starts, it inherits the program state 'as is'. E.g.
#the variable declarations above all apply - but changes to
#values within the program are 'thread local' unless the
#variable is defined as 'shared'.
#Behind the scenes - Thread::Queue are 'shared' arrays.

sub worker {
#NB - this will sit a loop indefinitely, until you close the queue.
#using $process_q -> end
#we do this once we've queued all the things we want to process
#and the sub completes and exits neatly.
#however if you _don't_ end it, this will sit waiting forever.
while ( my $server = $process_q->dequeue() ) {
chomp($server);
print threads->self()->tid() . ": pinging $server\n";
my $result = `/bin/ping -c 1 $server`;
if ($?) { $failed_q->enqueue($server) }
print $result;
}
}

#insert tasks into thread queue.
open( my $input_fh, "<", "server_list" ) or die $!;
$process_q->enqueue(<$input_fh>);
close($input_fh);

#we 'end' process_q - when we do, no more items may be inserted,
#and 'dequeue' returns 'undefined' when the queue is emptied.
#this means our worker threads (in their 'while' loop) will then exit.
$process_q->end();

#start some threads
for ( 1 .. $nthreads ) {
threads->create( \&worker );
}

#Wait for threads to all finish processing.
foreach my $thr ( threads->list() ) {
$thr->join();
}

#collate results. ('synchronise' operation)
while ( my $server = $failed_q->dequeue_nb() ) {
print "$server failed to ping\n";
}

可储存的

对于Storable,我认为这是一个单独的示例,因为移动数据非常方便。
use Storable qw ( freeze thaw );
use MyObject; #home made object.
use Thread::Queue;

my $work_q = Thread::Queue->new();

sub worker_thread {
while ( my $packed_item = $work_q->dequeue ) {
my $object = thaw($packed_item);
$object->run_some_methods();
$object->set_status("processed");
#maybe return $object via 'freeze' and a queue?
}
}

my $thr = threads->create( \&worker_thread );
my $newobject = MyObject->new("some_parameters");
$work_q->enqueue( freeze($newobject) );
$work_q->end();
$thr->join();

因为要在队列中传递对象,所以可以有效地在线程之间克隆对象。因此请记住,一旦对它的内部状态做了一些处理,您可能需要卡住它并以某种方式“返回”它。但这确实意味着您可以异步执行此操作,而无需仲裁锁定或共享内存。您可能还会发现能够“存储”,“检索”和对象很有用-这可以按您期望的那样工作。 (尽管我敢说您在检索存储的对象时可能需要注意模块版本和定义的属性的可用性)

fork

您的脚本会克隆自己,留下一个“ parent ”和“ child ”,然后 child 通常会发散并做一些不同的事情。这使用内置在 fork()中的Unix,因此经过了很好的优化,并且通常非常高效-但由于级别较低,因此很难进行大量数据传输。您将完成一些稍微复杂的事情以进行进程间通信-IPC。 (有关更多详细信息,请参见 perlipc )。这之所以有效是因为大多数 fork()实现都会执行惰性数据复制-仅在需要时才分配进程的内存空间,例如更改时。

因此,如果您要委派很多不需要 parent 太多监督的任务,那真的很好。例如-您可能 fork一个Web服务器,因为 child 正在读取文件并将其交付给特定的客户端,而父级则不太在乎。或者,如果您想花费大量的CPU时间来计算结果,而只将结果传回,则可能会这样做。

Windows也不支持它。

有用的库包括 Parallel::ForkManager

“ fork ”代码的基本示例如下所示:
#!/usr/bin/perl
use strict;
use warnings;
use Parallel::ForkManager;

my $concurrent_fork_limit = 4;

my $fork_manager = Parallel::ForkManager->new($concurrent_fork_limit);

foreach my $thing ( "fork", "spoon", "knife", "plate" ) {
my $pid = $fork_manager->start;
if ($pid) {
print "$$: Fork made a child with pid $pid\n";
} else {
print "$$: child process started, with a key of $thing ($pid)\n";
}
$fork_manager->finish;
}

$fork_manager->wait_all_children();

哪个最适合您?

因此,很难说出您要完成的目标的更多细节。这就是为什么StacKOverflow通常喜欢显示一些工作,您尝试过的方法等。

我通常会说:
  • 如果您需要传递数据,请使用线程。 Thread::Queue特别适合与Storable结合使用时。
  • 如果不这样做,则 fork (在Unix上)通常更快/更高效。 (但是,仅靠速度通常是不够的-首先编写可理解的内容,然后以速度为目标。通常并不重要)。

  • 避免在可能的情况下产生太多线程-它们在内存和创建开销上非常密集。与以重复方式创建短暂的新线程相比,以“ worker 线程”编程风格使用固定数量要好得多。 (另一方面, fork 实际上非常擅长此操作,因为它们不会复制您的整个过程)。

    我建议您在给出的方案中-您正在查看线程和队列。您的父进程可以通过 threads -> list()joincreate跟踪子线程以保持正确的编号。并且可以通过中央队列将数据提供给您的工作线程。或者有多个队列-每个“ child ”一个队列,并将其用作任务分配系统。

    关于perl - Perl用子守护程序守护,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26296206/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com