不要使用+=
紧密循环
这是你最大的水槽:
$ccMap[$companyCd] += $coceMap
当您使用一个哈希表添加到另一个哈希表时+
(or +=
就此而言),PowerShell 创建一个全新的哈希表:
# Create two different hashtables
$A = @{ Key1 = 'Value1' }
$B = @{ Key2 = 'Value2' }
# Let's save a second reference to the first table
$remember = $A
# Now let's use += to merge the two:
$A += $B
运行这个你会发现$B
and $remember
没有变化,但是$A
拥有两把钥匙 - 因此必须是一把新钥匙。
为了解决这个性能损失,请跳过构建$coceMap
完全,并颠倒顺序(如果不存在,则先构造哈希表,然后分配):
$ccMap=@{}
foreach($line in $ccDb)
{
$companyCd=$line.companyCd.trim()
$costCenterNbr=$line.costCenterNbr.trim()
$costCenterShortNm=$line.CostCenterShortNm.trim()
$costCenterLongDescr=$line.CostCenterLongDescr.trim()
# Create new hashtable if none exist, otherwise retrieve the existing one
if($ccMap.ContainsKey($companyCd))
{
$coceMap = $ccMap[$companyCd]
}
else
{
$coceMap = $ccMap[$companyCd] = @{}
}
$coceMap[$costCenterNbr] = @{
shortDesc=$costCenterShortNm
longDesc=$costCenterLongDescr
}
}
标杆管理+=
下面是一个简化的示例,显示了 10000 个具有 50 个不同键的项目的差异:
$data = @(
1..10000 |Select-Object @{Name='Company';Expression={Get-Random -Maximum 50}},@{Name='CostCenter';Expression={Get-Random}}
)
@(
Measure-Command {
$map = @{}
foreach($line in $data){
$entry = @{
$line.CostCenter = @{
Value = 123
}
}
if($map.ContainsKey($line.Company)){
$map[$line.Company] += $entry
}
else {
$map[$line.Company] = $entry
}
}
}
Measure-Command {
$map = @{}
foreach($line in $data){
if($map.ContainsKey($line.Company)){
$entry = $map[$line.Company]
}
else {
$entry = $map[$line.Company] = @{}
}
$entry[$line.CostCenter] = @{
Value = 123
}
}
}
) |select TotalMilliseconds
在我的笔记本电脑上给出:
TotalMilliseconds
-----------------
306.4218
47.8164
一般来说,如何识别这样的时间沉降?
有多种方法可以分析 PowerShell 的运行时行为,但这是我个人的首选:
- Install PSProfiler https://www.powershellgallery.com/packages/PSProfiler (Disclaimer: I'm the maintainer of
PSProfiler
):
Install-Module PSProfiler -Scope CurrentUser
- Use
Measure-Script
就像你一样Measure-Command
:
Measure-Script {
$map = @{}
foreach($line in $data){
$entry = @{
$line.CostCenter = @{
Value = 123
}
}
if($map.ContainsKey($line.Company)){
$map[$line.Company] += $entry
}
else {
$map[$line.Company] = $entry
}
}
}
- 等待代码完成
- 查看输出:
Anonymous ScriptBlock
Count Line Time Taken Statement
----- ---- ---------- ---------
0 1 00:00.0000000 {
1 2 00:00.0000187 $map = @{}
0 3 00:00.0000000
0 4 00:00.0000000 foreach($line in $data){
10000 5 00:00.0635585 $entry = @{
0 6 00:00.0000000 $line.CostCenter = @{
0 7 00:00.0000000 Value = 123
0 8 00:00.0000000 }
0 9 00:00.0000000 }
0 10 00:00.0000000
0 11 00:00.0000000 if($map.ContainsKey($line.Company)){
9950 12 00:00.3965227 $map[$line.Company] += $entry
0 13 00:00.0000000 }
0 14 00:00.0000000 else {
50 15 00:00.0002810 $map[$line.Company] = $entry
0 16 00:00.0000000 }
0 17 00:00.0000000 }
0 18 00:00.0000000 }
观察第 12 行占用的总执行时间最多 - 明显多于其他任何行:
9950 12 00:00.3965227 $map[$line.Company] += $entry