我必须在我的代码中使用守护进程。我需要一个控制守护进程,它不断检查数据库中的任务并监督子守护进程。控制守护进程必须将任务分配给子守护进程,控制任务,如果其中一个死亡,则创建新子进程等。子守护进程检查数据库以查找它们的任务(通过PID)。我应该如何为此目的实现守护进程?
答案 0 :(得分:12)
守护进程只是"后台进程的代码字,运行时间很长"。所以答案是'它取决于'。 Perl有两种主要的多处理方式:
将子程序作为线程运行,与主程序代码并行运行。 (然后可以监视线程状态)。
创建线程的开销更高,但它更适合于共享内存'样式多处理,例如当你来回传递大量数据时。有几个库使线程之间的信息传递非常简单。就个人而言,我非常喜欢Thread::Queue
,Thread::Semaphore
和Storable
。
特别是 - Storable
有freeze
和thaw
,可让您在队列中移动复杂的数据结构(例如对象/哈希),这非常有用。
基本线程示例:
#!/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();
因为您在队列中传递了对象,所以您可以在线程之间有效地克隆它。所以请记住,您可能需要冻结它并“返回”。一旦你对它的内部状态做了一些事情,它就会以某种方式完成。但它确实意味着您可以异步执行此操作,而无需仲裁锁定或共享内存。您可能还会发现能够存储&#39;和&#39;检索&#39;和对象 - 这可以像你期望的那样工作。 (虽然我敢说你可能需要注意模块版本与定义属性的可用性,如果你要检索存储的对象)
你的脚本克隆了自己,留下了一个父母&#39;和孩子&#39; - 然后孩子通常会发散并做出不同的事情。这使用内置于fork()
的Unix,因此经过优化并且通常非常高效 - 但由于它的级别较低,意味着很难进行大量的数据传输。您最终会做一些稍微复杂的事情来进行进程间通信 - IPC。 (有关详细信息,请参阅perlipc
)。它的效率至关重要,因为大多数fork()
实现都会执行惰性数据复制 - 您的进程的内存空间仅在需要时分配,例如:什么时候改变了。
因此,如果您想委派许多不需要父母监督的任务,那就非常好。例如 - 你可能fork
一个网络服务器,因为孩子正在阅读文件并将它们交付给特定的客户,而且父母并不在乎。或者,如果您想花费大量CPU时间来计算结果,并且只将结果传回去,那么您可能会这样做。
Windows上也不支持它。
有用的库包括Parallel::ForkManager
分叉的基本例子&#39;代码看起来有点像:
#!/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
结合使用时非常有用。
如果你没有,forks(在Unix上)通常更快/更有效。 (但快速独自通常不够 - 先写出可以理解的东西,然后以速度为目标。通常情况并不重要)。
尽可能避免产生太多线程 - 它们在内存和创建开销方面相当密集。你最好在一个工作线程中使用固定数字&#39;编程风格,而不是反复创建新的,短命的线程。 (另一方面 - 叉子实际上非常擅长这一点,因为它们不会复制整个过程。)
我建议在你给出的场景中 - 你正在查看线程和队列。您的父进程可以通过threads -> list()
和join
或create
跟踪子线程,以保留正确的号码。并且可以通过中央队列将数据提供给您的工作线程。或者有多个队列 - 每个孩子一个&#39;并将其用作任务分配系统。