【问题标题】:Perl6 Making an observable timerPerl6 制作一个可观察的计时器
【发布时间】:2018-06-28 09:20:00
【问题描述】:

我正在尝试使用计时器类编写观察者模式,该计时器类以给定的时间间隔调用其订阅者。一直在尝试理解 Perl6 中的 Promise 概念。

class Timer does Observable
{
    has Promise $!p;
    has Int $!interval;
    has Bool $!active = False;

    submethod BUILD(Int :$!interval) {}

    method start {
        $!p = Promise.start( {
            $!active = True;
            loop {
                sleep($!interval);
                @!action_listeners>>.actionPerformed(ActionEvent.new);
                if !$!active {$!p.keep}
            }
        });
    }

    method stop {
        $!active = False;
    }
}

观察者角色只是有一个包含订阅者的数组。当然,我应该创建一个方法来更新角色内的所有订阅者。

role Observable {
    has ActionListener @!action_listeners;

    method addActionListener(ActionListener $al){
        @!action_listeners.push($al);
    }

    method removeActionListener{
        @!action_listeners.pop;
    }
}

ActionListener 角色只有一个 actionPerformed 方法。 ActionEvent 类可能不是必需的,目前它只是一个空类。

role ActionListener
{
    method actionPerformed(ActionEvent $e) { ... }
}

从脚本运行:

my Subscriber $s = Subscriber.new;
my Timer $t = Timer.new(interval => 1);

$t.start;
$t.addActionListener($s);
$t.addActionListener(Subscriber.new);

.... #doing stuff that lasts for a while
$t.stop;

订阅者类实现 ActionListener 角色(有一个名为 actionPerformed 的方法)。

虽然这工作正常:订阅者的 actionPerformed 方法被调用,直到我调用计时器的 stop 方法。虽然没有适当的方法来删除给定的订阅者。另外我想知道是否有更好的方法来保持/打破承诺,从外部给定代码循环不定式。

我基本上想知道我是否会错过 Perl6 的内置功能?我是在重新发明轮子吗?

【问题讨论】:

  • 如果相关,您可以添加ActionListener 的代码吗?此外,loop 永远循环...
  • 当然 ActionListener 是一个简单的角色,定义了一个方法 (actionPerformed) 。打破循环的方法是遵守承诺(通过将 $!active 设置为 True)。同意这不是一个特别好的阻止它的方法。您是否建议循环仍在运行,即使调用它的 Promise 已被保留?
  • 并非如此。我没有看到你在远处做动作,从其他函数中设置一个类变量。为什么不使用 stop 来信守承诺,而不是设置该变量?如果没有更多的任务要听,你就不能遵守承诺吗?
  • 当数组@!action_listners.elems == 0 时结束承诺,当然是一种选择。虽然在添加动作监听器之前开始承诺,但会立即结束。
  • my $p = Promise.new; $p.then({ say 2 }); say 1; $p.keep; 1␤2␤ 如果你真的想了解 Perl 6 中的 Promises,暂时忘记 start 方法,因为它实际上只是简写形式:method start (&code) { my $p = Promise.new; $*SCHEDULER.cue({$p.keep(code())}); $p }(那里有一些区别,但这基本上就是它的作用)

标签: concurrency observer-pattern raku


【解决方案1】:

要进一步回答重新发明轮子的问题:您应该看看SupplySupplyObservable 的 Perl 6 术语,TapSubscription 的 Perl 6 术语。

为了获得一个定期调用订阅者的 observable,您可以使用the interval class method of the Supply type。您将在 .interval 调用的结果上调用 .tap 来注册一个代码块,以便在 Supply emits 值和 .tap 调用的结果是您的 Tap 对象时运行可以关闭订阅。

如果您想了解更多关于耗材的信息,These talk slides by Jonathan Worthington 可能会很有趣。

【讨论】:

  • OOC,如何停止间隔?通过关闭最后一个tap ?
【解决方案2】:

回答您的问题“我是在重新发明轮子吗?”。可能。

您实际上可以要求当前的ThreadPoolScheduler(又名$*SCHEDULER)提示一段代码以间隔运行:

my $canceller = $*SCHEDULER.cue( { say $++ }, every => 0.2 );
sleep 2;
# 0 1 2 3 4 5 6 7 8 9
$canceller.cancel;
say "stopped";  # no numbers should be seen afterward
# stopped    
sleep 1;        # keep from exiting immediately

这不涉及任何Promises,所以如果您的目标是了解更多关于Promises 的信息,那么这不是要走的路。如果您想创建观察者模式,这可能是最简洁的创建方式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多