3

我有一个包含 700 万个 XML 文件的设置,大小从几 KB 到几 MB 不等。总而言之,它大约有 180GB 的 XML 文件。我需要执行的工作是分析每个 XML 文件并确定文件是否包含 string <ref>,以及是否不将其从当前包含的 Chunk 文件夹中移出到 Referenceless 文件夹中。

我创建的脚本运行良好,但就我的目的而言它非常慢。它计划在大约 24 天内完成对所有 700 万个文件的分析,以每秒大约 3 个文件的速度进行。我可以在我的脚本中更改什么来获得更多性能吗?

此外,更复杂的是,我在我的服务器上没有正确的权限来运行 .PS1 文件,因此脚本需要能够在一个命令中从 PowerShell 运行。如果我有授权​​,我会设置权限。

# This script will iterate through the Chunk folders, removing pages that contain no 
# references and putting them into the Referenceless folder.

# Change this variable to start the program on a different chunk. This is the first   
# command to be run in Windows PowerShell. 
$chunknumber = 1
#This while loop is the second command to be run in Windows PowerShell. It will stop after completing Chunk 113.
while($chunknumber -le 113){
#Jumps the terminal to the correct folder.
cd C:\Wiki_Pages
#Creates an index for the chunk being worked on.
$items = Get-ChildItem -Path "Chunk_$chunknumber"
echo "Chunk $chunknumber Indexed"
#Jumps to chunk folder.
cd C:\Wiki_Pages\Chunk_$chunknumber
#Loops through the index. Each entry is one of the pages.
foreach ($page in $items){
#Creates a variable holding the page's content.
$content = Get-Content $page
#If the page has a reference, then it's echoed.
if($content | Select-String "<ref>" -quiet){echo "Referenced!"}
#if the page doesn't have a reference, it's copied to Referenceless then deleted.
else{
Copy-Item $page C:\Wiki_Pages\Referenceless -force
Remove-Item $page -force
echo "Moved to Referenceless!"
}
}
#The chunk number is increased by one and the cycle continues.
$chunknumber = $chunknumber + 1
}

我对 PowerShell 知之甚少,昨天是我第一次打开这个程序。

4

4 回答 4

4

您将希望将-ReadCount 0参数添加到您的Get-Content命令中以加快它们的速度(这很有帮助)。我从这篇很棒的文章中学到了这个技巧,该文章显示foreach在整个文件的内容上运行比尝试通过管道解析它更快。

此外,您可以使用Set-ExecutionPolicy Bypass -Scope Process在当前 Powershell 会话中运行脚本,而无需额外权限!

于 2012-06-30T19:07:31.667 回答
2

PowerShell 管道可能比本机系统调用慢得多。

PowerShell:管道性能

在本文中,在 PowerShell 上执行的两个等效命令和经典 Windows 命令提示符之间执行性能测试。

PS> grep [0-9] numbers.txt | wc -l > $null
CMD> cmd /c "grep [0-9] numbers.txt | wc -l > nul"

这是它的输出示例。

PS C:\temp> 1..5 | % { .\perf.ps1 ([Math]::Pow(10, $_)) }

10 iterations

   30 ms  (   0 lines / ms)  grep in PS
   15 ms  (   1 lines / ms)  grep in cmd.exe

100 iterations

   28 ms  (   4 lines / ms)  grep in PS
   12 ms  (   8 lines / ms)  grep in cmd.exe

1000 iterations

  147 ms  (   7 lines / ms)  grep in PS
   11 ms  (  89 lines / ms)  grep in cmd.exe

10000 iterations

 1347 ms  (   7 lines / ms)  grep in PS
   13 ms  ( 786 lines / ms)  grep in cmd.exe

100000 iterations

13410 ms  (   7 lines / ms)  grep in PS
   22 ms  (4580 lines / ms)  grep in cmd.exe

编辑:这个问题的原始答案提到了管道性能以及其他一些建议。为了使这篇文章简洁,我删除了其他与管道性能实际上没有任何关系的建议。

于 2012-06-30T16:12:42.383 回答
0

我会尝试使用 Start-Job cmdlet 一次解析 5 个文件。有很多关于 PowerShell Jobs 的优秀文章。如果由于某种原因没有帮助,并且您遇到 I/O 或实际资源瓶颈,您甚至可以使用 Start-Job 和 WinRM 在其他机器上启动工作程序。

于 2012-07-01T17:14:28.310 回答
0

在开始优化之前,您需要准确确定需要优化的位置。您是否受 I/O 限制(读取每个文件需要多长时间)?内存受限(可能不是)?CPU 受限(搜索内容的时间)?

你说这些是 XML 文件;您是否测试过将文件读入 XML 对象(而不是纯文本),并<ref>通过 XPath 定位节点?然后,您将拥有:

$content = [xml](Get-Content $page)
#If the page has a reference, then it's echoed.
if($content.SelectSingleNode("//ref") -quiet){echo "Referenced!"}

如果您有空闲的 CPU、内存和 I/O 资源,您可能会通过并行搜索多个文件看到一些改进。请参阅有关并行运行多个作业的讨论。显然你不能同时运行大量,但是通过一些测试你可以找到最佳位置(可能在 3-5 附近)。里面的一切都是foreach ($page in $items){工作的脚本块。

于 2012-07-01T01:11:32.753 回答