【问题标题】:PowerShell Parallel vs Sequential Jobs - Sequential is faster?PowerShell 并行与顺序作业 - 顺序更快?
【发布时间】:2013-11-05 01:02:39
【问题描述】:

我正在尝试实现 Windows EventLogs 的多线程解析,并且在双核系统上我发现顺序代码比并行代码快得多。这些是例子:

顺序:

$start = Get-Date

$code1 = { Get-WinEvent -Path "D:\logs\hostname-security-20131003005914.evtx" -MaxEvents 200 }
$code2 = { Get-WinEvent -Path "D:\logs\hostname-security-20131003015906.evtx" -MaxEvents 200 }

$result1 = & $code1
$result2 = & $code2

$end = Get-Date
$timespan = $end - $start
$seconds = $timespan.TotalSeconds
Write-Host "This took me $seconds seconds in all."

平行:

$start = Get-Date

$code1 = { Get-WinEvent -Path "D:\logs\hostname-security-20131003005914.evtx" -MaxEvents 200 }
$code2 = { Get-WinEvent -Path "D:\logs\hostname-security-20131003015906.evtx" -MaxEvents 200 }

$job1 = Start-Job -ScriptBlock $code1 
$job2 = Start-Job -ScriptBlock $code2 

$alljobs = Wait-Job $job1, $job2
$result1, $result2 = Receive-Job $alljobs

$end = Get-Date
$timespan = $end - $start

$seconds = $timespan.TotalSeconds
Write-Host "This took me $seconds seconds in all."

顺序代码运行时间约为 5 秒(CPU 使用率接近 50%),而并行代码运行时间约为 19 秒(CPU 使用率接近 100%)。我已经回显了结果以确保它们都是正确的并且看起来很好。

我正在运行 Windows 8。PowerShell 详细信息是:

名称值
---- -----
PS版本 3.0
WSManStackVersion 3.0
序列化版本 1.1.0.1
CLRVersion 4.0.30319.18051
构建版本 6.2.9200.16628
PSCompatibleVersions {1.0、2.0、3.0}
PSRemotingProtocolVersion 2.2

有什么想法吗?

编辑: 产生这个难题的不仅仅是 Get-WinEvent;我尝试使用 Get-ChildItem 得到相同的结果。

但是,将其作为要执行的代码,并行代码运行得更快(如预期的那样):

$code1 = { Start-Sleep -Seconds 5; "A" }
$code2 = { Start-Sleep -Seconds 12; "B" }

连续 17.002 秒。 并行 14.2 秒。

【问题讨论】:

    标签: powershell


    【解决方案1】:

    当您使用 Powershell 作业时,Powershell 会创建一个新会话来运行脚本块。

    试试这个:

    measure-command { start-job -ScriptBlock {} }
    

    这是您创建工作所花费的时间。如果您正在使用该作业的任务花费的时间少于此时间,那么您最好在本地会话中按顺序运行这些任务。

    【讨论】:

    • 虽然这是有道理的,但不幸的是它并不能解释我所看到的。创造就业机会所花费的时间非常短。为了延长任务本身,我将 -MaxEvents 增加到 2000,现在在我的工作计算机(四核 i7)上运行它。在并行代码中创建 $job1 所需的时间为 0.18 秒,$job2 为 0.11 秒。 CPU 使用率接近 50%(使用 2 个内核)。大约需要 49 秒。顺序代码在 18 秒内运行,CPU 使用率约为 25%。
    • 我尝试在并行代码中运行单个作业。它也花了大约 49 秒。添加获取日期 |在 Get-WinEvent 显示之前和之后的脚本块的 Out-File 显示它占用了时间,而不是等待作业或接收作业。因此,Get-WinEvent 在并行作业与顺序代码中的脚本块内运行时的行为是不同的。在我的 Windows 8.1 机器 Server 2008R2 上,相同的时间差异很明显(我怀疑桌面操作系统可能将并行进程置于后台,但在服务器上遇到相同的结果消除了这一点)。跨度>
    • @Rob 执行此操作:在您的 Receive-Jobs 之后添加 -Keep,然后单独查看每个作业。有一个 beginTime 和 endTime 时间戳。这将使您更准确地了解工作本身的情况,我想您会感到惊讶。顺便说一句,您是否尝试过在 Powershell 工作流程中使用并行块?可能更适合您。
    • @CrownedJitter:感谢您的建议。使用 -keep 实际上给出了与我的 Get-Date hack 相同的结果!两个作业的 PSBeginTime 和 PSEndTime 完全相同。只是出于某种奇怪的原因,他们需要更长的时间。我已经编辑了原始帖子,以表明如果您只是使用 Start-Sleep,情况并非如此。一旦脚本块涉及实际 CPU 时间,并行需要更长的时间。我的能力目前还没有扩展到运行空间/工作流,但我会看看。
    【解决方案2】:

    对于您创建的每个作业,都会创建一个新的 powershell 进程,该进程需要资源来进行调度、加载 .net 运行时等。它会产生大量 CPU 开销,并且每个作业至少需要 20mb+ 内存。

    因此,工作更适合:

    • 持续数分钟或数小时的长时间运行脚本。

    • 在多台计算机上并行运行代码。

    【讨论】:

    • 谢谢。我延长了流程,但我仍然遇到反直觉的结果,如对上述评论的回复所述。
    【解决方案3】:

    Thomas Lee http://tfl09.blogspot.com/2010/12/powershell-jobs.html 的进一步文档支持这里已经说过的内容:

    “每次运行 PowerShell 作业(无论是在 ISE 还是控制台中),PowerShell 都会创建一个 PowerShell.exe 实例来执行脚本或脚本块。这意味着每个作业都会带来一些开销——进程创建有 CPU/IO/Memory 要求。但是如果您可以在单独的进程中运行多个任务,那么借助 Window 的多处理功能,这些作业可以并行运行,因此总体时间要短得多。至少在理论上!

    视情况而定。如果正在执行的任务使用大量资源来实际执行,那么让多个任务并行运行会提高资源利用率。具体来说,如果有超过一两个“繁重”任务,您会发现系统正在大量分页。这种分页实际上可能最终会减慢执行速度,以至于并行化的好处被分页成本所抵消。”

    【讨论】:

    • 我希望能够通过分页来解释它,但我的系统没有这样做(系统运行很少,8GB RAM,SSD 上的四核 i7)。你能试试这些只在内存中运行的例子吗?顺序:link 和并行:link - 如果您不相信长度,可以调整数字。将这些保存为单独的 PS1 文件并在单独的 PS 窗口中运行。当并行代码运行时,两个启动的 PS 进程在进程监视器上分别消耗约 46-48% 的 CPU。代码花费的时间是顺序代码的近 10 倍。
    • 如果我在 PowerGUI 中运行它,Parallel 会更快。
    猜你喜欢
    • 2021-09-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-23
    • 2019-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-07
    相关资源
    最近更新 更多