Net::LDAP 和 Parallel::Forkmanager 可以一起工作吗?
Can Net::LDAP and Parallel::Forkmanager work together?
我需要通过 Net::LDAP. I have something that works well. However, in an attempt to speed up things, I tried to query the different servers in parallel, using Parallel::Forkmanager 在 perl 中查询不同的 LDAP 服务器 - 当我这样做时,事情不起作用。
我收到以下类型的错误:
decode error 02<=>30 0 8 at /Users/myname/perl5/perlbrew/perls/perl-5.18.2/lib/site_perl/5.18.2/Convert/ASN1/_decode.pm line 113, <> line 18.
decode error 43<=>30 0 8 at /Users/myname/perl5/perlbrew/perls/perl-5.18.2/lib/site_perl/5.18.2/Convert/ASN1/_decode.pm line 113, <> line 25.
在获取搜索响应的行:
$mesg = $ldap->search( base => $dn, filter => '(CN=*)');
我很纳闷
换句话说,为什么会失败:
use Net::LDAP;
use Parallel::Forkmanager;
...; # bind LDAP servers
while (<>) {
chop;
my $dn = $_;
foreach my $ldap (@servers) {
my $pid;
$pid = $pm->start and next; # do the fork
print $dn, $pid;
my $mesg;
try {
$mesg = $ldap->search( base => $dn, filter => '(CN=*)');
} catch {
...;
}
$pm->finish;
}
}
同时:
use Net::LDAP;
...; # bind LDAP servers
while (<>) {
chop;
my $dn = $_;
foreach my $ldap (@servers) {
print $dn;
my $mesg;
try {
$mesg = $ldap->search( base => $dn, filter => '(CN=*)');
} catch {
...;
}
}
}
完美运行?
虽然 fork
ing 与 thread
ing 没有完全相同的线程安全问题 - 但仍有一些地方存在问题。我认为这就是困扰你的地方 - 你的 Net::LDAP
objects 是在 parent 线程中创建的,但是当你 fork 时(有效地)克隆到每个线程。
这意味着在你的代码中——如果你的名字列表足够快,一个新的分支将尝试重用一个非常真实的可能性现有的 Net::LDAP 个连接,在上一个连接完成之前。
防止这种情况的简单方法是调用 wait_all_children
以确保在下一个查询开始之前完成所有并行 LDAP 查询。
如果您将 LDAP 绑定放在 ForkManager
循环中,您是否仍然遇到同样的问题?我很欣赏这是一个潜在的开销,因为您将绑定每个迭代,但如果解决了这个问题,我建议这是因为 Net::LDAP
在 fork 之间共享相同的文件描述符。
下一个最佳解决方案是采用 'worker' 模型,其中您有一堆 'workers',每个都有它们的 LDAP 连接来进行查询。使用线程比 fork
ing 更容易 - 有点像这样:
#!/usr/bin/perl
use strict;
use warnings;
use threads;
use Thread::Queue;
sub server_worker {
my ( $hostname, $q_ref ) = @_;
## connect LDAP to $hostname;
while ( my $dn = $$q_ref->dequeue ) {
#query $dn
}
}
my @queues;
foreach my $server (@list_of_servers) {
my $server_q = Threads::Queue->new();
push( @queues, $server_q );
threads->create( \&server_worker, $hostname, $server_q );
}
while ( my $dn = <STDIN> ) {
chomp($dn);
foreach my $q (@queues) {
$q->enqueue($dn);
}
}
foreach my $q ( @queues ) {
$q -> end;
}
foreach my $thr ( threads->list ) {
$thr->join();
}
用分叉做类似的事情应该可行:
#!/usr/bin/perl
use strict;
use warnings;
use IO::Pipe;
use Parallel::ForkManager;
use Net::LDAP;
my @list_of_servers = qw ( servername servenama anotherserver );
my $pm = Parallel::ForkManager -> new ( scalar @list_of_servers );
my %pipe_for;
foreach my $server ( @list_of_servers ) {
my $pipe = IO::Pipe -> new();
my $pid = pm -> start;
if ( $pid ) {
print "$$: parent\n";
$pipe -> writer -> autoflush;
$pipe_for{$server} = $pipe;
}
else {
print "$$ child connecting to $server\n";
$pipe -> reader -> autoflush;
close ( STDIN ); #because this is a child.
#Net::LDAP setup
while ( my $item = <$pipe> ) {
chomp ( $item );
#ldap_search $item;
}
}
$pm -> finish;
}
然后发送东西:
for my $number ( 1..10 ) {
foreach my $pipe ( values %pipe_for ) {
print {$pipe} "test$number\n";
}
}
$pm -> wait_all_children();
编辑:注意 - 自动刷新很重要,否则 IO 缓冲并且看起来不像它在工作。我很确定在 child 中关闭 STDIN 可能是个好主意,但如果他们不使用它,可能并不是绝对必要的。
我需要通过 Net::LDAP. I have something that works well. However, in an attempt to speed up things, I tried to query the different servers in parallel, using Parallel::Forkmanager 在 perl 中查询不同的 LDAP 服务器 - 当我这样做时,事情不起作用。
我收到以下类型的错误:
decode error 02<=>30 0 8 at /Users/myname/perl5/perlbrew/perls/perl-5.18.2/lib/site_perl/5.18.2/Convert/ASN1/_decode.pm line 113, <> line 18.
decode error 43<=>30 0 8 at /Users/myname/perl5/perlbrew/perls/perl-5.18.2/lib/site_perl/5.18.2/Convert/ASN1/_decode.pm line 113, <> line 25.
在获取搜索响应的行:
$mesg = $ldap->search( base => $dn, filter => '(CN=*)');
我很纳闷
换句话说,为什么会失败:
use Net::LDAP;
use Parallel::Forkmanager;
...; # bind LDAP servers
while (<>) {
chop;
my $dn = $_;
foreach my $ldap (@servers) {
my $pid;
$pid = $pm->start and next; # do the fork
print $dn, $pid;
my $mesg;
try {
$mesg = $ldap->search( base => $dn, filter => '(CN=*)');
} catch {
...;
}
$pm->finish;
}
}
同时:
use Net::LDAP;
...; # bind LDAP servers
while (<>) {
chop;
my $dn = $_;
foreach my $ldap (@servers) {
print $dn;
my $mesg;
try {
$mesg = $ldap->search( base => $dn, filter => '(CN=*)');
} catch {
...;
}
}
}
完美运行?
虽然 fork
ing 与 thread
ing 没有完全相同的线程安全问题 - 但仍有一些地方存在问题。我认为这就是困扰你的地方 - 你的 Net::LDAP
objects 是在 parent 线程中创建的,但是当你 fork 时(有效地)克隆到每个线程。
这意味着在你的代码中——如果你的名字列表足够快,一个新的分支将尝试重用一个非常真实的可能性现有的 Net::LDAP 个连接,在上一个连接完成之前。
防止这种情况的简单方法是调用 wait_all_children
以确保在下一个查询开始之前完成所有并行 LDAP 查询。
如果您将 LDAP 绑定放在 ForkManager
循环中,您是否仍然遇到同样的问题?我很欣赏这是一个潜在的开销,因为您将绑定每个迭代,但如果解决了这个问题,我建议这是因为 Net::LDAP
在 fork 之间共享相同的文件描述符。
下一个最佳解决方案是采用 'worker' 模型,其中您有一堆 'workers',每个都有它们的 LDAP 连接来进行查询。使用线程比 fork
ing 更容易 - 有点像这样:
#!/usr/bin/perl
use strict;
use warnings;
use threads;
use Thread::Queue;
sub server_worker {
my ( $hostname, $q_ref ) = @_;
## connect LDAP to $hostname;
while ( my $dn = $$q_ref->dequeue ) {
#query $dn
}
}
my @queues;
foreach my $server (@list_of_servers) {
my $server_q = Threads::Queue->new();
push( @queues, $server_q );
threads->create( \&server_worker, $hostname, $server_q );
}
while ( my $dn = <STDIN> ) {
chomp($dn);
foreach my $q (@queues) {
$q->enqueue($dn);
}
}
foreach my $q ( @queues ) {
$q -> end;
}
foreach my $thr ( threads->list ) {
$thr->join();
}
用分叉做类似的事情应该可行:
#!/usr/bin/perl
use strict;
use warnings;
use IO::Pipe;
use Parallel::ForkManager;
use Net::LDAP;
my @list_of_servers = qw ( servername servenama anotherserver );
my $pm = Parallel::ForkManager -> new ( scalar @list_of_servers );
my %pipe_for;
foreach my $server ( @list_of_servers ) {
my $pipe = IO::Pipe -> new();
my $pid = pm -> start;
if ( $pid ) {
print "$$: parent\n";
$pipe -> writer -> autoflush;
$pipe_for{$server} = $pipe;
}
else {
print "$$ child connecting to $server\n";
$pipe -> reader -> autoflush;
close ( STDIN ); #because this is a child.
#Net::LDAP setup
while ( my $item = <$pipe> ) {
chomp ( $item );
#ldap_search $item;
}
}
$pm -> finish;
}
然后发送东西:
for my $number ( 1..10 ) {
foreach my $pipe ( values %pipe_for ) {
print {$pipe} "test$number\n";
}
}
$pm -> wait_all_children();
编辑:注意 - 自动刷新很重要,否则 IO 缓冲并且看起来不像它在工作。我很确定在 child 中关闭 STDIN 可能是个好主意,但如果他们不使用它,可能并不是绝对必要的。