【问题标题】:How can I terminate a loop started in a BEGIN block?如何终止在 BEGIN 块中开始的循环?
【发布时间】:2022-09-24 17:49:38
【问题描述】:

我想在应用程序加载/初始化时显示进度条。

此代码不起作用,但应该让您了解什么 我正在努力完成。

my Bool $done-compiling = False;
BEGIN {
    start repeat {
        print \'*\';
        sleep 0.33;
    } until $done-compiling;
};

INIT {
    $done-compiling = True;
};

是否触发了我可以在 BEGIN 块中响应的事件?

    标签: progress-bar splash-screen raku


    【解决方案1】:

    Liz 根据您编写的代码提供了一个解决方案,修复了您原始代码中的错误。

    这是一个更简单的版本:

    BEGIN start repeat { print '*'; sleep 0.33 } until INIT True
    

    (您可能会认为 INIT True 是一些特殊功能,但它只是从返回值的移相器的工作方式中自然而然地消失了。)

    【讨论】:

      【解决方案2】:

      我认为代码没问题。如果你模拟加载,你会看到一个 * 的进度条:

      my Bool $done-compiling;
      BEGIN {
          start repeat {
              print '*';
              sleep 0.33;
          } until $done-compiling;
      }
      
      BEGIN sleep 3; # simulate compilation / loading
      
      INIT $done-compiling = True;
      

      INIT 块中设置标志就足够了!我想您可以考虑执行 INIT 块作为您正在寻找的事件?

      【讨论】:

      • 注意输出默认是缓冲的,所以*s 的打印很可能不会及时出现;您可能希望将其添加为 BEGIN 块的第一行: BEGIN { $*OUT.out-buffer = False;如果需要,您可以在完成 BEGIN/INIT 时间工作后重新启用缓冲。
      • 使用 Welcome to Rakudo™ v2022.07。实施 Raku® 编程语言 v6.d。基于 MoarVM 版本 2022.07 构建。在 macos Monterey 12.5 上当我将这些行添加到您的程序中时:prompt "?? "; say "Done."; 我得到以下输出:(我在提示符处输入了hello world):**********?? *****h*e*ll*o*****wo*r*ld******** Done. 程序开始执行后进度条继续运行。
      • @Coke:如果 $*OUT.t,很确定它是无缓冲的。至少对我来说是这样。
      • @JimBollinger 啊,是的,我的错。 INIT 会将标志设置为True,然后开始常规执行。这是在第 1 行,标志被重置为False。删除= False(就像我刚刚在示例中所做的那样)它应该可以按您的意愿工作。 :-)
      【解决方案3】:

      你已经得到了两个有效的答案。但是它们都依赖于跨不同线程使用变量,这总是让我有点紧张。鉴于我们在这里需要多个线程,我可能会求助于 Raku 有用的并发原语之一。这是对使用Promise 的已接受答案的一个非常小的更改:

      my Promise $done-compiling;
      BEGIN {
          $done-compiling .= new;
          start repeat {
              print '*';
              sleep 0.33;
          } until $done-compiling ~~ Kept;
      }
      
      BEGIN sleep 3; # simulate compilation / loading
      
      INIT $done-compiling.keep;
      

      【讨论】:

      • 谢谢 - 这不仅优雅,而且我了解了更多关于 Promises 的知识!
      • @codesections“它们都依赖于在不同线程中使用变量”我在想INIT 移相器不会——不能——产生一个(非Nil)值,直到封闭的compunit 的运行阶段开始(并且假设代码将在 main/MAIN compunit 中)。我什至做了各种测试,试图反驳我的想法,但无济于事。但是我没有检查编译器的代码。大概你做到了,或者你知道一些我不知道的事情。无论如何,如果您在我的答案下方而不是在这里的评论中进行解释,那么对于以后的读者来说将是最好的。 (然后我会删除这条评论。)
      • @raiph我实际上不确定您提出的观点。它可能完全安全,因为你说的原因。但我知道涉及多个线程(请参阅tio.run/##K0gtyjH7/9/…)。而且,正如我所说,在没有并发安全包装器的情况下跨线程共享数据让我感到紧张——也就是说,即使它很好,我也不想分心向自己证明这一点。
      • 您不确定INIT 应该做什么吗?我假设它是一个移相器,它会在程序中的所有编译单元完成编译阶段之后在运行阶段(也就是运行程序)尽快触发。或者 Rakudo 或我的大脑是否有错误?我提到我已经测试了我的解决方案以澄清我已经检查了后者。我尽我所能相信它会奏效,而且现在仍然如此。它会是疯狂的如果没有。但是当我如此自信时,我的本能反应是尝试反驳我的想法,以防 Rakudo 或我的大脑出现问题。你不确定什么?
      • “跨线程共享数据” 跨线程共享数据在哪里? “没有并发安全包装器让我感到紧张”。介绍并发让我紧张。因为你已经介绍了它是不必要的。 “我宁愿不要分心向自己证明这一点”但你确实有这种分心。您已经介绍了并发性。你确定 A) 你的大脑没有问题——你没有犯错 B) Rakudo 没有问题——你引入的并发性有一天不会出错吗?
      猜你喜欢
      • 1970-01-01
      • 2014-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-26
      相关资源
      最近更新 更多