performance - 为什么这个 PowerShell 代码 (Invoke-WebRequest/getElementsByTagName) 在我的机器上如此缓慢,但在其他机器上却没有?

标签 performance powershell powershell-3.0

我在 PowerShell 中编写了一些屏幕抓取代码,令我惊讶的是它花了大约 30 秒来解析几个 HTML 表格。我将其剥离以试图找出所有时间都花在了哪里,它似乎在 getElementsByTagName 调用中。

我在下面包含了一个脚本,在我的家庭桌面、我的工作桌面和我的家庭平板上,每次迭代大约需要 1-2 秒(完整结果粘贴在下面)。但是,PowerShell 社区中的其他人报告的时间要短得多(每次迭代只有几毫秒)。

我正在努力寻找缩小问题范围的方法,而且似乎没有适用于 OS/PS/.NET/IE 版本的模式。

我目前运行它的桌面是全新的 Windows 8 安装,仅安装了 PS3 和 .NET 4.5(以及所有 Windows 更新补丁)。没有 Visual Studio 。没有 PowerShell 配置文件。

$url = "http://www.icy-veins.com/restoration-shaman-wow-pve-healing-gear-loot-best-in-slot"
$response = (iwr $url).ParsedHtml

# Loop through the h2 tags
$response.body.getElementsByTagName("h2") | foreach {

    # Get the table that comes after the heading
    $slotTable = $_.nextSibling

    # Grab the rows from the table, skipping the first row (column headers)
    measure-command { $rows = $slotTable.getElementsByTagName("tr") | select -Skip 1 } | select TotalMilliseconds
}

我的桌面结果(工作 PC 和平板电脑给出的结果几乎相同):

TotalMilliseconds
-----------------
        1575.7633
        2371.5566
        1073.7552
        2307.8844
        1779.5518
        1063.9977
        1588.5112
        1372.4927
        1248.7245
        1718.3555
         3283.843
        2931.1616
        2557.8595
        1230.5093
         995.2934

然而,有些人在Google+ PowerShell community reported results like this :

 TotalMilliseconds
 -----------------
           76.9098
          112.6745
           56.6522
          140.5845
           84.9599
           48.6669
           79.9283
           73.4511
           94.0683
           81.4443
           147.809
          139.2805
          111.4078
           56.3881
           41.3386

我已经尝试过 PowerShell ISE 和标准控制台,没有区别。对于正在进行的工作,这些时间似乎有点过分,并且从 Google+ community 中的帖子来看,它可以走得更快!

最佳答案

请参阅我的评论:https://connect.microsoft.com/PowerShell/feedback/details/778371/invoke-webrequest-getelementsbytagname-is-incredibly-slow-on-some-machines#tabs

我在 64 位模式下运行脚本同样缓慢,但在 32 位模式下运行时,一切都非常快!

Lee Holmes 重现了这个问题,这是他的文章

“问题在于他将 COM 对象通过管道传输到另一个 cmdlet – 在本例中为 Select-Object。发生这种情况时,我们尝试通过属性名称绑定(bind)参数。枚举 COM 对象的属性名称非常慢 – 所以我们我们将 86% 的时间花在两个非常基本的 CLR API 调用上:

(…) //从 COM 类型中获取函数描述 typeinfo.GetFuncDesc(index, out pFuncDesc); (…) //从 COM 函数描述中获取函数名 typeinfo.GetDocumentation(funcdesc.memid, out strName, out strDoc, out id, out strHelp); (……)

我们也许可以通过缓存在这里做一些聪明的事情。

解决方法是不通过管道输入 Select-Object,而是使用语言特性:

# Grab the rows from the table, skipping the first row (column headers)
$allRows = @($slotTable.getElementsByTagName("tr"))
$rows = $allRows[1..$allRows.Count]

关于performance - 为什么这个 PowerShell 代码 (Invoke-WebRequest/getElementsByTagName) 在我的机器上如此缓慢,但在其他机器上却没有?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14202054/

相关文章:

PHP + MySQL + 重复日历事件

xml - Powershell 添加内容截断输出

PowerShell 从远程 PC 删除桌面项目

powershell - 使用 Send-MailMessage 将变量插入 html 正文

database - 用于简单读/写(无更新)场景的最佳高性能数据库

具有多个 union 和 group by 的 MySQL 查询

sql - 如何从 SQL 查询中快速获得结果

powershell - 使用 powershell 获取 Azure 账单信息?

powershell - 具有约束的Powershell随机获取

powershell - Scriptblock 中的全局范围变量为空