我有一些行为相当奇怪的代码。
我在一个函数中,我声明了一个嵌套的函数,它应该检查一些东西是否正常。如果不是那么它应该睡五秒钟并再次自我调用。
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:对于那些说我的递归在这种情况下奇怪而无用的人 - 由于种种原因,我需要使用这样的格式(它更适合我的需要,因为,在我得到这个工作之后,我会修改它以添加各种东西并重用它,而且,对于我的想法,函数似乎是最好的选择。)答案 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);
请在评论中告诉我如何更新变量,我将帮助解决。