嵌套递归函数

时间:2015-08-03 14:07:58

标签: perl recursion while-loop vmware

我有一些行为相当奇怪的代码。

我在一个函数中,我声明了一个嵌套的函数,它应该检查一些东西是否正常。如果不是那么它应该睡五秒钟并再次自我调用。

sub stop {

    sub wait_for_stop {
        my $vm_view = shift;

        if ( $vm_view->runtime->powerState->val ne "poweredOff" ) {
            debug("...");
            sleep(5);
            wait_for_stop();
        }
    }

    debug("Waiting for the VM to stop");
    wait_for_stop( @$vm_views[0] );
}

因此,在导致if条件内的递归的调用中,如果我放入参数(如函数定义所期望的那样),就像这样:

wait_for_stop($vm_view);

我得到一个无限循环。

如果我在没有参数的情况下离开它,就像上面的代码示例一样,它会按预期工作。

后续调用中$vm_view不应为空吗?或者上次使用的值($vm_view->runtime->powerState->val)?这两种情况都会导致意外行为和错误。

但它没有任何参数。那为什么呢?有什么东西我错过了perldoc吗?

EDIT1:实际上,$vm_views的值确实发生了变化,因此这不是无限循环的原因。

一般性澄清

我正在使用VMware SDK。 $vm_views对象包含VM详细信息。我正在轮询其中一种方法来检测更改,在这种特殊情况下,我需要知道机器何时关闭。因此,由于缺乏更好的方法,我每隔5秒拨一次电话,直到值满意为止。

我的目的是停止VM,进行仅在关闭时进行的修改,然后启动它。

实际问题

当我没有传递参数时,该块按预期工作 - 它等待值poweredOff(VM关闭),并继续,这没有多大意义,至少对我

在我将$vm_view作为参数的情况下,我得到一个无限循环(因为我正在调用一个方法,所以该值仍然会被更改)。

所以我想知道为什么函数有效,当第一次调用后,$vm_view应该是undef,因此,陷入无限循环? [undef ne“poweredOff” - >睡觉 - >递归到死亡]

为什么,当我通过预期值时,它会被卡住?

PS:对于那些说我的递归在这种情况下奇怪而无用的人 - 由于种种原因,我需要使用这样的格式(它更适合我的需要,因为,在我得到这个工作之后,我会修改它以添加各种东西并重用它,而且,对于我的想法,函数似乎是最好的选择。)

3 个答案:

答案 0 :(得分:2)

在进行像递归之类的更奇特的事情之前,你应该总是看看你的标准工具。这里你需要的只是一个while循环

值得注意的是,@$vm_views[0]应该是$$vm_views[0]),或者更好,$vm_views->[0]。并且通过在中定义子程序来获得任何东西 - 效果与之后单独声明的效果相同

如果$vm_view->runtime->powerState->val永远不会返回poweredOff,我会期望无限循环,而下面的代码不会解决这个问题。在等待状态更改之前,我没有看到任何告诉VM停止的代码。这是对的吗?

当您在没有任何参数的情况下调用wait_for_stop时,我不明白为什么您说您的代码正常工作。你会得到致命的错误

Can't call method "runtime" on an undefined value

你的程序将停止。你发布的真实代码是什么?

这将按照您的意图行事。我也认为它更容易阅读

use strict;
use warnings;

my $vm_views;

sub stop {

    debug ("Waiting for the VM to stop");

    my $vm_view = $vm_views->[0];
    while ( $vm_view->runtime->powerState->val ne 'poweredOff' ) {
        debug('...');
        sleep 5;
    }
}

答案 1 :(得分:0)

我认为你最好不要递归地调用wait_for_stop()。这种方式可能会更好地为您服务:

sub stop
{
    sub wait_for_stop
    {
            my $vm_view = shift;
            if ($vm_view->runtime->powerState->val ne "poweredOff")
            {
                    debug("...");
                    #sleep(5);
                    #wait_for_stop();
                    return 0;
            }
            return 1;
    }
    debug ("Waiting for the VM to stop");
    until(wait_for_stop(@$vm_views[0]))
    {
         sleep(5);
    }
}

您的旧方式相当混乱,我认为您没有将$vm_view变量传递给递归子例程调用。

答案 2 :(得分:-1)

更新

我试过在这里阅读: https://www.vmware.com/support/developer/viperltoolkit/doc/perl_toolkit_guide.html#step3

它说:

  

运行脚本时,VI Perl Toolkit运行时会检查   环境变量,配置文件内容和命令行   条目(按此顺序)以获取必要的连接设置详细信息。如果   这些覆盖都不可用,运行时使用默认值   (见表1)设置连接。

所以,"运行时"即使未定义vm对象,是否正在使用默认连接详细信息?也许? 这仍然无法解释为什么在参数传递时它不起作用。 您需要更好地了解VM SDK。您对递归和函数参数的使用的逻辑很好。

此外,页面为:https://www.vmware.com/support/developer/viperltoolkit/doc/perl_toolkit_guide.html

说 -

  

VI Perl Toolkit视图有几个你应该具备的特性   在编写自己的脚本时请记住。具体来说,一个观点:

  • 是Perl对象

  • 包含与属性相关的属性和方法 服务器端受管对象的操作

  • 是一个或多个服务器端托管对象的静态副本,以及 这样的(静态),不会自动更新为对象的状态 在服务器上更改。

那么" vm"函数返回是一个静态副本,可以从脚本更新。在传递$ vm_view时打电话可能会更新吗?

旧答案: 问题不是你从Perl文档中错过的。问题在于您对递归的理解。

递归的目的是继续运行,直到$ vm_view-> runtime-> powerState-> val成为" PoweredOff"然后级联回来。如果您没有更新该值,它将一直运行。

当你说:

  

我得到一个无限循环。

您是否在if条件中更新$vm_view? 否则,每次调用函数时变量都是相同的,因此最终会无限循环。

  

如果我在没有参数的情况下离开它,就像上面的代码示例一样   按预期工作。

它如何按预期工作?有什么期待?该函数无法知道您的$ vm_view正在更新的值。

我已经简化了代码,添加了更新一个简单的变量(类似于你的$ vm_view)并进行了测试。用它来了解发生的事情:

sub wait_for_stop
{
    my $vm_view = shift;

    if ($vm_view < 10){
        print "debug...\n";
        sleep(5);
        $vm_view++; // update $vm_view->runtime->powerState->val here
                    // so that it becomes "poweredOff" at some point of time
                    // and breaks the recursion
        wait_for_stop($vm_view);
    }
}

wait_for_stop(1);

请在评论中告诉我如何更新变量,我将帮助解决。