我的设置包含700万个XML文件,大小从几KB到多MB不等。总而言之,它是大约180GB的XML文件。我需要执行的工作是分析每个XML文件并确定该文件是否包含字符串<ref>
,以及是否不将其从当前包含在Referenceless文件夹中的Chunk文件夹中移出。
我创建的脚本运行得很好,但对于我的目的来说它非常慢。它计划在大约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知之甚少,昨天是我第一次打开程序。
答案 0 :(得分:4)
您需要将-ReadCount 0
参数添加到Get-Content
命令中以加速它们(它有很大帮助)。我从this一篇很棒的文章中了解到了这一提示,该文章显示在整个文件的内容上运行foreach
比尝试通过管道解析它更快。
此外,您可以使用Set-ExecutionPolicy Bypass -Scope Process
在当前的Powershell会话中运行脚本,而无需额外的权限!
答案 1 :(得分:2)
PowerShell管道可能明显慢于本机系统调用。
PowerShell: pipeline performance
在本文中,在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
编辑:这个问题的原始答案提到了管道性能以及其他一些建议。为了使这篇文章简明扼要,我删除了其他与管道性能无关的建议。
答案 2 :(得分:1)
在开始优化之前,您需要准确确定需要优化的位置。您是否受I / O限制(读取每个文件需要多长时间)?内存限制(可能不是)? CPU限制(搜索内容的时间)?
你说这些是XML文件;你测试过将文件读入XML对象(而不是纯文本),并通过XPath定位<ref>
节点吗?然后你会:
$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资源,您可以通过并行搜索多个文件来看到一些改进。有关并行运行多个作业的信息,请参阅this discussion。显然你不能同时运行大量的数字,但通过一些测试你可以找到最佳位置(可能在3-5附近)。 foreach ($page in $items){
内的所有内容都是作业的脚本块。
答案 3 :(得分:0)
我将尝试使用Start-Job cmdlet一次解析5个文件。有很多关于PowerShell Jobs的优秀文章。如果由于某些原因没有帮助,并且您遇到I / O或实际资源瓶颈,您甚至可以使用Start-Job和WinRM来启动其他计算机上的工作。