在等待远程数据时读取STDIN;下载远程数据时终止

时间:2016-09-03 13:19:19

标签: perl concurrency parallel-processing stdin

我有一个简单的perl脚本:

#!/usr/bin/env perl

use strict;
use Data::Dumper;
use utf8;
binmode( STDOUT, ":utf8" );
$|++;

my $localBookmarks = {
    a => "local bookmark A",
    b => "local bookmark B",
    c => "local bookmark C",
};
print Dumper $localBookmarks;

my $remoteBookmarks = getRemoteBookmarks();
print Dumper $remoteBookmarks;

print "choose a bookmark: ";
my $answer = <STDIN>;
print "You want: $answer";
# process $answer...

sub getRemoteBookmarks
{
    # Net::SSH::Perl connection; exec command; parse it; return it
    # lets just simulate this
    sleep( 5 );
    return { d => "remote bookmark D", e => "remote bookmark E" };
}

输出结果为:

$ perl test.pl
$VAR1 = {
          'b' => 'local bookmark B',
          'a' => 'local bookmark A',
          'c' => 'local bookmark C'
        };
$VAR1 = {
          'd' => 'remote bookmark D',
          'e' => 'remote bookmark E'
        };
choose a bookmark:

当然print Dumper $localBookmarks之后会有一个沉默5秒钟。

在等待&#34;远程书签&#34;时,是否可以在打印&#34;本地书签&#34;后立即阅读<STDIN>?如果我知道这次我需要本地书签(我不必等待几秒钟下载)。否则,当&#34;远程书签&#34;下载后,应终止当前<STDIN>,打印下载的书签,并且 - 再次 - 在底部应该有<STDIN>。这可能与perl有关吗?

2 个答案:

答案 0 :(得分:3)

有很多方法可以做到这一点。一个更明显的方法是生成一个线程来进行远程工作,并且在您从STDIN读取之后,并且假设您无法在那里找到答案,请加入该线程(以确保它的顺序)完成)并检查那里。该线程需要完成actions中已有的所有操作,并删除&#34;选择书签&#34; line(通常打印getRemoteBookmarks就足够了),打印出新组的翻转器,并打印出新的&#34;选择一个书签&#34;条目。

如果已经做出选择,在线程之间共享变量等等,那么阻止线程打印任何东西需要一些额外的修复,但这是一般的想法。

另一种选择是通过事件处理来处理这个问题。您基本上同时拥有输入(使用Term::ReadLine中的事件处理 - 请参阅Term::ReadLine::Event了解如何使用各种事件模块执行此操作)以及您的ssh同时进行。这避免了一些线程共享等等,因为一切都发生在同一个线程中。

无论哪种方式,你的脚本都会变得简单得多,你可能真的会更好地打印出来&#34;收集信息,请等待&#34;在开始时,收集本地和远程的所有选项,然后打印出选项。从成本/收益的角度来看,就是这样。

祝你好运。

答案 1 :(得分:2)

这是一个使用IPC::Open3打开读取远程书签的单个子进程的简单示例。当孩子完成后,它会将书签存储在一个文件中(另一种方法是使用线程,管道或文件句柄进行通信,但我认为这会使程序稍微复杂化)。当子进程终止时,父进程将收到CHLD信号,这将导致父进程退出其输入循环并从磁盘读取远程书签。然后父级重新进入输入循环:

use feature qw(say);
use strict;
use warnings;
use Data::Dumper;
use IPC::Open3;
use Symbol qw(gensym);
use Storable qw(retrieve);

local $SIG{CHLD} = sub {
    die "\nBackground process finished..\n";
};

my $child1 = start_reading_remote_bookmarks(  );
my $local_bookmarks = {
    a => "local bookmark A",
    b => "local bookmark B",
    c => "local bookmark C",
};
print Dumper $local_bookmarks;
eval {
    run_input_loop();
};
if ($@) {
    print "\n";
    my $remote_bookmarks = retrieve('bookmarks.dat');
    print Dumper $remote_bookmarks;
    run_input_loop();
}

sub run_input_loop {
    while (1) {
        print "Choose a bookmark: ";
        chomp(my $answer = <STDIN>);
        say "You want: $answer";
        # process $answer...
    }
}

sub start_reading_remote_bookmarks {
    my $cmd = 'get_bookmarks.pl';
    my $cherr = gensym;
    my $pid = open3( my $chin, my $chout, $cherr, $cmd );
    return { pid => $pid, kid_in => $chin, kid_out => $chout, kid_err => $cherr };
}

其中get_bookmarks.pl

use strict;
use warnings;
use Storable qw(store);

sleep 5;
my $fn = 'bookmarks.dat';
store { d => "remote bookmark D", e => "remote bookmark E" }, $fn;