首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >带有子守护进程的Perl守护进程

带有子守护进程的Perl守护进程
EN

Stack Overflow用户
提问于 2014-10-10 09:31:04
回答 1查看 2.3K关注 0票数 6

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-10-10 10:24:52

Daemon只是“后台进程运行了很长时间”的代码。所以答案是“视情况而定”。Perl有两种主要的多处理方法:

穿线

您以线程的形式运行一个子程序,并与主程序代码并行。(然后只监视线程状态)。

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

特别是- Storablefreezethaw,它们允许您在队列中移动复杂的数据结构(例如对象/散列),这非常有用。

基本线程示例:

代码语言:javascript
复制
#!/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";
}

可存储

谈到可存储性时,我认为这是一个值得单独举的例子,因为移动数据非常方便。

代码语言:javascript
复制
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()中构建的Unix,因此它得到了很好的优化,而且通常效率很高--但是由于它的级别很低,这意味着很难进行大量的数据传输。最后,您将完成一些稍微复杂的事情来进行进程间通信-- IPC。(更多细节请参见perlipc )。它非常有效,尤其是因为大多数fork()实现都会为进程分配延迟的数据复制内存空间,例如,当它被更改时。

因此,如果您希望委派许多不需要家长进行太多监督的任务,这是非常好的。例如,您可能会fork一个web服务器,因为子服务器正在读取文件并将它们传递给特定的客户端,而父服务器并不关心这些文件。或者,如果您想花费大量CPU时间计算结果,并且只将结果传回,您可能会这样做。

Windows上也不支持它。

有用的库包括Parallel::ForkManager

一个基本的“分叉”代码示例看起来有点像这样:

代码语言:javascript
复制
#!/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相结合时,是很好的选择。
  • 如果没有,分叉(在Unix上)通常更快/更高效。(但光靠速度是不够的--先写些可以理解的东西,然后再写速度。)这通常并不重要)。

避免在可能的情况下产生过多的线程--它们在内存和创建开销上相当密集。在“工作线程”的编程风格中使用固定的数字要比反复创建新的、短暂的线程要好得多。(另一方面,叉子实际上很擅长这个,因为它们没有复制你的整个过程)。

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

票数 14
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26296206

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档