使用 Start-Job 时本地函数调用不起作用 [英] Local Function Calls Not Working When Making Use of Start-Job

查看:60
本文介绍了使用 Start-Job 时本地函数调用不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

       function F2([String]$var2)
        {
         .........
         .........
        }

       function F1([String]$var1)
        {
         .........
         F2 $var2
         .........
        }

       ..................
       ..................

      while ($i -le $count)
       {
        F1 "dir$i"
        Start-Job -ScriptBlock ${function:F1} -ArgumentList @($i)
        $i = $i + 1
       }

在下面的代码片段中,我想开始一项工作并为 while 循环的每次迭代运行 F1.尽管 F1 中定义的内容工作正常,但通过 ScriptBlock 完成后,F1 对 F2 的调用似乎没有通过.

In the following snippet, I'd like to start a job and run F1 for every iteration of the while loop. Although what's defined in F1 works fine, the call by F1 to F2 doesn't seem to go through when done via the ScriptBlock.

我在这里遗漏了什么吗?

Is there something I'm missing here ?

更新 1

我尝试实施您的建议,以实现一些相当简单明了的事情,即使用作业同时在目录中创建文件.

I tried to implement your suggestion to achieve something rather simple and straightforward, create files in directories simultaneously using jobs.

$dirname = "E:\TEST3\dir_"
$filename = "file_"
$i=1

$moduledef = {
function makeFiles([String]$dirname)
 {
  for ($i -le 5000)
   {
    echo "WASSSUP !!" >> "$dirnaname\$filename$i.txt" 
    $i++ 
   }
 }

function makeDir([String]$dirname)
 {
    mkdir "$dirname$i"
    makeFiles "$dirname$i"
    $i++ 
 }

} # END OF $moduledef

New-Module -Name MyFunctions -ScriptBlock $moduledef

while($i -le 10)
 {  
  Start-Job -ScriptBlock { 
    param([String]$jobArg)
    New-Module -Name MyFunctions -ScriptBlock $Using:moduledef
    makeDir $jobArg
    } -ArgumentList @("$dirname$i")
  $i++
 }
Get-Job | Wait-Job 

这里的问题是作业失败了(我在下面粘贴了其中一个),知道我在这里做错了什么吗?

The issue here is that the jobs failed (I've pasted one of them below), any idea what I'm doing wrong here ?

HasMoreData   : True
StatusMessage : 
Location      : localhost
Command       :  
                    param([String]$jobArg)
                    New-Module -Name MyFunctions -ScriptBlock $Using:moduledef
                    makeDir $jobArg

JobStateInfo  : Failed
Finished      : System.Threading.ManualResetEvent
InstanceId    : e79a6489-cad3-47a6-b6f4-8a207d32c187
Id            : 79
Name          : Job79
ChildJobs     : {Job80}
PSBeginTime   : 4/14/2018 9:52:01 PM
PSEndTime     : 4/14/2018 9:52:02 PM
PSJobTypeName : BackgroundJob
Output        : {}
Error         : {}
Progress      : {}
Verbose       : {}
Debug         : {}
Warning       : {}
Information   : {}
State         : Failed

更新 2

我包含了一个 Receive-Job,这只是错误的一部分.我想弄清楚,但把它贴在这里希望你能帮我.

I included a Receive-Job and this is just a part of the error. I'm trying to figure it out but pasting it here hoping you can help me out.

PSPath            : Microsoft.PowerShell.Core\FileSystem::E:\TEST3\dir10
PSParentPath      : Microsoft.PowerShell.Core\FileSystem::E:\TEST3
PSChildName       : dir10
PSDrive           : E
PSProvider        : Microsoft.PowerShell.Core\FileSystem
PSIsContainer     : True
Mode              : d-----
BaseName          : dir10
Target            : {}
LinkType          : 
RunspaceId        : 434aa380-b888-4ca5-897e-75a88e1f6560
Name              : dir10
FullName          : E:\TEST3\dir10
Parent            : TEST3
Exists            : True
Root              : E:\
Extension         : 
CreationTime      : 4/14/2018 9:29:12 PM
CreationTimeUtc   : 4/14/2018 3:59:12 PM
LastAccessTime    : 4/14/2018 9:29:12 PM
LastAccessTimeUtc : 4/14/2018 3:59:12 PM
LastWriteTime     : 4/14/2018 9:29:12 PM
LastWriteTimeUtc  : 4/14/2018 3:59:12 PM
Attributes        : Directory

The term 'makeFiles' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
    + CategoryInfo          : ObjectNotFound: (makeFiles:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException
    + PSComputerName        : localhost

Cannot bind parameter 'ScriptBlock'. Cannot convert the "
function makeFiles([String]$dirname)
 {
  for ($i -le 5000)
   {
    echo "WASSSUP !!" >> "$dirnaname\$filename$i.txt" 
    $i++ 
   }
 }
function makeDir([String]$dirname)

推荐答案

这实际上是 与 Dong Mao 相同的答案,这是在这里首先,但我把它写在副本上,却没有意识到这是在这里.

This is practically the same answer as Dong Mao's, which was here first, but I wrote it on the duplicate without realizing this was here.

无论如何,这种方法(使用模块)可以更好地解决代码缩放和重复问题.

Anyway, this method (using modules) may better address the scaling and duplication of code issue.

并不是说 F2 超出范围,而是它甚至不存在于工作中.

It's not so much that F2 is out of scope, it's that it doesn't even exist in the job.

作业作为单独的进程运行,因此除非您明确指定,否则调用进程中不会包含任何内容.

Jobs are run as separate processes, so nothing is included from the calling process unless you explicitly give it.

当您引用 ${function:F1} 时,您使用的是 PSDrive 形式的变量.本质上,它等同于 Get-Content -LiteralPath Function:\F1.

When you reference ${function:F1} you're using the PSDrive form of variable. In essence, it is the equivalent of Get-Content -LiteralPath Function:\F1.

如果您查看返回的内容,您会看到 1) 它是一个 [ScriptBlock](这正是 Start-Job 所需的类型)s -ScriptBlock 参数),但您也会看到它是函数的内容;它甚至不包括名称.

If you look at what is returned, you'll see that 1) it's a [ScriptBlock] (which is exactly the type you need for Start-Job's -ScriptBlock parameter), but you'll also see that it is the function's contents; it doesn't even include the name.

这意味着在作业中您直接执行函数体,但实际上并没有调用函数.

This means that in the job you're directly executing the body of the function but you are not actually calling a function.

您可以解决这个问题,重新生成函数定义部分,定义函数,或者只是在脚本块中重新定义 F2.这将很快开始变得混乱.

You could work around this re-generating the function definition part, defining the functions, or just defining F2 over again in the script block. This will start to get messy quickly.

我的建议是将您的函数分解为系统上可用的模块,然后在脚本块内,只需调用 Import-Module MyFunctions 即可.

My recommendation is to break your functions out into a module that is available on the system, then inside the script block, just call Import-Module MyFunctions and they will be available.

如果您不想经历拥有单独文件的过程,并希望保留它,您可以即时创建一个模块.只需将您的函数定义为脚本中的一个模块,如果您愿意,可以在工作中再做一次.像这样:

If you don't want to go through that process of having separate files, and want to keep it contained, you can create a module on the fly. Just define your functions as a module in your script, and if you like, do it again in the job. Something like this:

$moduleDefinition = {
    function F2([String]$var2)
    {
        "~$var2~"
    }

    function F1([String]$var1)
    {
        F2 $var1
    }
}

# this makes the module loaded in this context
New-Module -Name MyFunctions -ScriptBlock $moduleDefinition

while ($i -le $count)
{
    F1 "dir$i"
    Start-Job -ScriptBlock { 
        param([String]$jobArg)

        $modDef = [ScriptBlock]::Create($Using:moduleDefinition)    
        New-Module -Name MyFunctions -ScriptBlock $modDef

        F1 $jobArg
    } -ArgumentList @($i)
    $i = $i + 1
}

这篇关于使用 Start-Job 时本地函数调用不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆