0

快速故事:为了尝试使用 powershell,我正在尝试学习如何有效地对脚本进行多线程处理。

现在我知道如何开始工作并将变量传递给我的第二个脚本,但是我决定尝试找出如何解决这个问题:

start-job ((Split-Path -parent $PSCommandPath) + "\someScript.ps1") -ArgumentList (,$argList)

进入这个:

start-job (. ((Split-Path -parent $PSCommandPath) + "\someScript.ps1")) -ArgumentList (,$argList)

原因是我在父脚本中声明了一个变量,如下所示:

New-Variable var -value 0 -Option AllScope

并在子脚本中:var = "something" 第一个启动作业传递了我的参数,但子进程没有设置全局“var”变量

第二个没有传递我的参数,但子脚本设置了在父级中定义的全局变量就好了。$argList 变量将在第二个启动作业中填充到这行代码,但在执行该行之后,调试显示 $argList 变量为空,我得到“Start-Job:无法将参数绑定到参数” ScriptBlock',因为它是空的。”

为了论证起见,假设直到指定的代码行,变量都包含它们应该包含的数据。

有人可以帮我解决这两种尝试的问题吗?谷歌未能就我的问题给我任何具体的答案。提前感谢我能得到的任何帮助。

编辑: usingStart-Job (. ((Split-Path -parent $PSCommandPath) + "\someScript.ps1") $argList) 实现了我的目标,但是Start-Job : Cannot bind argument to parameter 'ScriptBlock' because it is null. 即使参数在脚本块中并且子脚本正在获取和处理参数,我也会继续得到。

4

1 回答 1

0

当您调用Start-Job时,脚本会在完全独立的范围(PowerShell 运行空间)中运行。您不能直接通过 dot-source 调用脚本Start-Job。您必须让外部脚本处理传入的参数 via -ArgumentList,然后将其返回给原始主机 Runspace via Receive-Job

这是一个完整的例子:

$a = 1;
$Job = Start-Job -FilePath C:\test\script.ps1 -ArgumentList $a;


Write-Host -Object "Before: $a"; # Before
Wait-Job -Job $Job;
$a = Receive-Job -Job $Job -Keep;
Write-Host -Object "After: $a"; # After

c:\test\script.ps1

这是文件的内容c:\test\script.ps1

Write-Output -InputObject (([int]$args[0]) += 5);

线程和运行空间探索

如果您想证明我之前关于Start-Job创建新线程和 PowerShell 运行空间以及新的观点,请Thread运行以下脚本:

# 1. Declare a thread block that retrieves the Runspace ID & ThreadID
$ThreadBlock = { 
    [runspace]::DefaultRunspace.InstanceId.ToString();
    [System.Threading.Thread]::CurrentThread.ManagedThreadId; 
    };

# 2. Start a job and wait for it to finish
$Job = Start-Job -ScriptBlock $ThreadBlock;
[void](Wait-Job -Job $Job);
Receive-Job -Job $Job -Keep;

# 3. Call the same ScriptBlock locally
& $ThreadBlock;

# 4. Note the differences in the Runspace InstanceIDs and ThreadIDs

在作业完成前接收结果

您可以Receive-Job在 PowerShell 作业完成之前多次调用以检索结果。这是一个理论上如何工作的示例:

$ScriptBlock = { 
    1..5 | % { Start-Sleep -Seconds 2; Write-Output -InputObject $_; };
};

$Job = Start-Job -ScriptBlock $ScriptBlock;

while ($Job.JobStateInfo.State -notin ([System.Management.Automation.JobState]::Completed,[System.Management.Automation.JobState]::Failed)) {
    Start-Sleep -Seconds 3;
    $Results = Receive-Job -Job $Job;
    Write-Host -Object ('Received {0} items: {1}' -f $Results.Count, ($Results -join ' '));
}
于 2014-01-06T18:34:30.817 回答