【问题标题】:Perl Multiple SubroutinesPerl 多个子例程
【发布时间】:2014-03-06 08:11:21
【问题描述】:

对于 perl 专家来说,这可能是一个简单的问题 -

我正在尝试运行一个在逻辑上应该执行此操作的脚本>

Main
{
 While (true)
  Call Sub A
  Call Sub B
  Call Sub C
}

Sub A
{
Go execute a method A for whatever it needs to do ---
before next time method A runs it need to wait atleast 60 seconds but i still want to call method B in these 60 seconds.
}

Sub B
{
  Go execute a method B for whatever it needs to do ---
before next time method b runs it need to wait atleast 60 seconds but i still want to call method C in these 60 seconds in mean time.

}

Sub C
{
  Go execute a method C for whatever it needs to do ---
before next time method C runs it need to wait atleast 60 seconds at this moment control should be back in Main and wait for first 60 seconds of A to expire so that Sub A can be called
}

我的问题: 问:我能做到这一点的最佳和优化方式是什么?

问:如果我在每个 sub 中设置 sleep 60,那么即使在 60 秒到期之前,下一个 sub 也不会被调用,这将延迟整体处理。

问:我希望每 60 秒按顺序调用 3 个潜艇

Q 最后,如果我需要每 60 秒呼叫 2 个 subs 并且每小时最后一个 subs - 我该怎么做?

评论 - 我的想法是将 UTC 作为一个变量并将其存储在一个变量中,并在时间到期时继续检查时间,而不是调用单个潜艇,但不确定它是否是运行代码的最佳方式。

【问题讨论】:

  • 每个子程序都需要几秒钟吗?总和总是小于 60 秒吗?如果 A 在 60 秒内完成但 B 还没有完成,是否应该再次运行 A? C呢?你可以使用多个线程,所以有一个 A 线程以不高于每 60 秒一次的频率运行 A,一个 B 线程用于 B,一个 C 线程用于 C?
  • 使用线程可能是这里的方式,但请记住,如果您的 subs 与公共全局变量混合(全局不仅在相应的 sub 中),您必须确保没有两个线程试图同时修改同一个变量。这不是一项简单的任务。
  • 所以理论上没有一个应该花费超过几秒钟(这些是 SOAP 调用),我的测试表明它可能需要很少的几秒钟,并且绝对总和不会等于或大于 60 秒。但是我想再次采取最佳实践,而不是依赖我的想法.....所以我可以使用多线程程序(我不知道怎么做?)如果可能的话,我需要一些伪代码帮助在 perl 中。并解释它是如何工作的......感谢并感谢您的回复。
  • perldoc.perl.org/perlthrtut.html 如果你不明白里面的内容,问。
  • 你想在 A 结束之前给 B 打电话吗?线程的答案是假设的,但在我看来,您希望它们是连续的,这意味着您不想想要使用线程。

标签: perl


【解决方案1】:

在子程序内部记录它最后一次运行的时间,如果需要,等待下一次执行:

use feature 'state';

my $sleep_duration = 60; # seconds

sub foo {
   state $last_execution = 0;
   my $remaining = $last_execution + $sleep_duration - time;
   sleep $remaining if $remaining > 0;
   $last_execution = time;

   ...; # normal processing for this sub
}

【讨论】:

    【解决方案2】:

    您可能想use threads。下面的 sn-p 可能会给你一个起点。由于您有四个 Qs 而不是一个,因此我不会详细介绍它们。

    #!/usr/bin/perl
    
    use warnings;
    use strict;
    use threads;
    
    my @t = (
      threads->create(\&A),
      threads->create(\&B),
      threads->create(\&C)
    );
    
    $t[0] -> join();
    $t[1] -> join();
    $t[2] -> join();
    
    sub A {
      for my $i (1 .. 10) {
         print "A $i\n";
         sleep 60;
      }
    }
    
    sub B {
      for my $i (1 .. 20) {
         print "B $i\n";
         sleep 60;
      }
    }
    
    sub C {
      for my $i (1 .. 3) {
         print "C $i\n";
         sleep 60;
      }
    }
    

    【讨论】:

    • 所以基本上你的例子中的每个线程都是从主线程开始的子线程,并且将是独立的并且具有不重叠或影响其他人的睡眠持续时间。
    【解决方案3】:

    使用 Amon 的思想,但在函数外有睡眠逻辑,

    sub get_sleeper {
    
      my ($sleep_duration) = @_;
    
      my $last_execution = 0;
      return sub {
        my $remaining = $last_execution + $sleep_duration - time();
        sleep $remaining if $remaining >0;
        $last_execution = time();
      };
    }
    
    my ($sleepA, $sleepB, $sleepC) = map get_sleeper(60), 1..3;
    while (1) {
      $sleepA->(); SubA();
      $sleepB->(); SubB();
      $sleepC->(); SubC();
    }
    

    【讨论】:

      【解决方案4】:

      这两个答案都很好,但一种中间方法是:(从 amon 的答案中窃取)

      use feature 'state';
      
      my $sleep_duration = 60; # seconds
      
      sub foo {
         state $last_execution = 0;
         my $remaining = $last_execution + $sleep_duration - time;
         if ($remaining > 0)
         {
             return "Waiting";  # Make sure main checks for this to know whether the sub ran.
         }
      
         ...; # normal processing for this sub
      }
      

      这将允许您在这个等待时运行下一个子而不需要多个线程。但当然,这意味着这艘潜艇只有在其他两个有机会之后才会运行。这意味着您混淆了订单,并根据订阅者的不同,需要超过 60 秒的时间才能进行下一次通话。

      【讨论】:

      • 好吧,除了我需要小心全局变量之外,使用线程的任何警告都是有意义的
      • @Nik 不是。有时它有点繁琐。但是,如果您打算继续编程,那么学习使用和理解多线程无论如何都是重要且有益的。所以我想说,在你知道的脚本中这样做,并且像这个问题这样的复杂性有限,可能是一个很好的深入研究的机会。这些概念在所有语言中大多相似。即使让它像你想要的那样使用线程工作需要花费你几个小时的时间,这也是绝对值得的,所以继续吧。如果您遇到无法按预期工作的事情(一开始可能会发生的事情^^),请回来
      • 同意并感谢大家 - 我会试一试,这可能是我编写干净代码的一个很好的学习机会。
      猜你喜欢
      • 1970-01-01
      • 2013-03-28
      • 2019-10-05
      • 2011-08-06
      • 1970-01-01
      • 1970-01-01
      • 2015-01-18
      • 2023-03-30
      相关资源
      最近更新 更多