2017-01-20 16 views
0

私はPowerShellスクリプトを使って、pingログをグラフデータに変換しています。Powershellの配列が遅い

スクリプトが正常に動作しているが、非常にゆっくりと配列操作によって引き起こさ稼働。

スクリプトは10Kラインファイル上で実行した場合、それは約7秒かかります。 配列操作が削除された場合、完了までに要する時間はそれよりも短くなります。

私は一時的な配列を使用せずに、呼び出し元の関数にデータを返すために別の解決策を探しています。入力ログの

例:

02.01.2017-14:53:54> Reply from 8.8.8.8: bytes=32 time=184ms TTL=57 
02.01.2017-14:53:54> Reply from 8.8.8.8: bytes=32 time=18ms TTL=57 
02.01.2017-14:53:59> Request timed out. 
02.01.2017-14:54:01> Reply from 192.168.2.186: Destination host unreachable. 
02.01.2017-14:54:05> Request timed out. 
02.01.2017-14:54:07> Reply from 192.168.2.186: Destination host unreachable. 

スクリプト:実は

function Convert-V4PingLog2ChartData 
{ 
    param($V4PingLogFile, $AvarageRespondTime, $ChartCounter) 
    $ConvertedData="" 
    $var=Get-Content $V4PingLogFile 
    $varArray=$var.split("`n") 
    $varArray=$varArray | Select-Object -Skip 2 

    $CommandExecuteTime=Measure-Command{ 

    $pattern = "^([0-9]{2})\.([0-9]{2})\.([0-9]{4})-([0-9]{2}):([0-9]{2}):([0-9]{2})> Reply from [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}: bytes=32 time=([0-9]{1,4})ms TTL=[0-9]{1,3}$"; 
    $pattern2="^([0-9]{2})\.([0-9]{2})\.([0-9]{4})-([0-9]{2}):([0-9]{2}):([0-9]{2})> (Request timed out.|Reply from [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}: Destination host unreachable.)$" 

    foreach($nextLine in $varArray) 
    { 
     if($nextLine -like "* time=*")  
     { 
      $ConvertedData+=$nextLine -replace $pattern, "data$ChartCounter.addRow([new Date(`$3, `$2, `$1, `$4, `$5, `$6, 00), `$7, $AvarageRespondTime]);" 
     } 
     else 
     { 
      $ConvertedData+=$nextLine -replace $pattern2, "data$ChartCounter.addRow([new Date(`$3, `$2, `$1, `$4, `$5, `$6, 00), 0, $AvarageRespondTime]);" 
     } 
    } 
    } 
    Write-Host $CommandExecuteTime 
    return $ConvertedData 
} 

答えて

1

は、あなたが文字列ではなく、配列に追加しているが、それは同様に遅いことがバインドされています。

変更この:この中

$ConvertedData="" 
... 
foreach($nextLine in $varArray) 
{ 
    if($nextLine -like "* time=*")  
    { 
     $ConvertedData+=$nextLine -replace ... 
    } 
    else 
    { 
     $ConvertedData+=$nextLine -replace ... 
    } 
} 

$ConvertedData = foreach ($nextLine in $varArray) { 
    if ($nextLine -like "* time=*") { 
     $nextLine -replace ... 
    } else { 
     $nextLine -replace ... 
    } 
} 
$ConvertedData -join "`n" 

は、物事をスピードアップします。

+0

ありがとう、それは完全に動作します – Krisz

+0

良い1つのAnsgar :) –

0

。このような何かを試してみてください。

[email protected]" 
{Timelog*:02.01.2017-14:53:54}> {TypeRow:Reply} {Detail:from {IP:8.8.8.8}: {Detailbytes:bytes=32} {Detailtime:time=184ms} {DetailTTL:TTL=57}} 
{Timelog*:15.15.2018-20:30:00}> {TypeRow:Reply} {Detail:from {IP:18.28.38.48}: {Detailbytes:bytes=32} {Detailtime:time=184ms} {DetailTTL:TTL=57}} 
{Timelog*:02.01.2017-14:53:54}> {TypeRow:Reply} {Detail:from {IP:1.2.345.678}: {Detailbytes:bytes=32} {Detailtime:time=184ms} {DetailTTL:TTL=57}} 
{Timelog*:04.01.2017-14:53:59}> {TypeRow:Request} {Detail:{Message:timed out.}} 
{Timelog*:03.01.2017-14:54:01}> {TypeRow:Reply} {Detail:from {IP:192.168.2.186}: {Message:Destination host unreachable.}} 
{Timelog*:12.01.2017-14:54:05}> {TypeRow:Request} {Detail:{Message:timed out.}} 
{Timelog*:02.01.2017-14:54:07}> {TypeRow:Reply} {Detail:from {IP:255.255.255.255}: {Message:Destination host unreachable.}} 
"@ 

get-Content C:\temp\File.txt | ConvertFrom-String -TemplateContent $template | 
%{ 
    [pscustomobject]@{ 
    Timelog=$_.Timelog 
    TypeRow=$_.TypeRow 
    IP=$_.Message.IP 
    Detailbytes=if ($_.Detail.Message -ne $null) {''} else {$_.Detail.Detailbytes} 
    Detailtime=if ($_.Detail.Message -ne $null) {''} else {$_.Detail.Detailtime} 
    DetailTTL=if ($_.Detail.Message -ne $null) {''} else {$_.Detail.DetailTTL} 
    Error=$_.Detail.Message 
    } 
} | Format-Table 
+0

ありがとう、素晴らしいソリューションと完全に異なるアプローチ:)、私は100Kのラインログとわずか23秒で試してみました。 – Krisz

0

はまず、アンスガーが書いたように、あなたは文字列ではなく配列に追加しています。しかし、問題はどちらの場合も同じです。 .NETでは、配列と文字列の両方が不変(配列サイズではなく内容)です。配列や文字列に何かを追加するたびに、古いコンテンツが新しいメモリ位置にコピーされ、新しいデータが追加されます。あなたが手動であることを期待し、最終的なサイズに、配列のサイズを変更する場合は、この問題を克服することができますアレイで

。サイズ変更は配列 をコピーしますが、追加するたびに1回実行するのではありません。速度差はHUGEになることができます!私は次のような結果が

Days    : 0 
Hours    : 0 
Minutes   : 0 
Seconds   : 3 
Milliseconds  : 534 
Ticks    : 35342407 
TotalDays   : 4,09055636574074E-05 
TotalHours  : 0,000981733527777778 
TotalMinutes  : 0,0589040116666667 
TotalSeconds  : 3,5342407 
TotalMilliseconds : 3534,2407 

さて、次のコマンドを考えてみました。このコマンドを実行する

$a = @(); Measure-Command { for($i = 0; $i -lt 10000; $i++) { $a += $i } } 

は空の配列に10000の項目を追加し、次のコマンドを考えてみましょう。まず、ArrayオブジェクトのResize静的メンバー関数を使用して配列のサイズを変更し、インデックスを使用して10000を設定します。

$b = @(); Measure-Command { 
    [array]::Resize([ref]$b,10000); 
    for($i = 0; $i -lt 10000; $i++) { $b[$i] = $i } 
} 

結果は以下のとおりです。

Days    : 0 
Hours    : 0 
Minutes   : 0 
Seconds   : 0 
Milliseconds  : 40 
Ticks    : 402365 
TotalDays   : 4,65700231481481E-07 
TotalHours  : 1,11768055555556E-05 
TotalMinutes  : 0,000670608333333333 
TotalSeconds  : 0,0402365 
TotalMilliseconds : 40,2365 

わずか40ミリ秒まで3.5秒から実行時ドロップ!

あなたはアンスガーの技術で、この技術を組み合わせることができます。配列のサイズを変更し、結果をサイズ変更された配列に追加し、最後に配列を大きな文字列に結合します。

備考新しいサイズを毎回与えることで、必要なだけサイズ変更を呼び出すことができます。現在の配列サイズは、配列のLengthプロパティを使用して取得できます。 制限に達してより多くのスペースが必要な場合は、サイズ変更を呼び出して別の大きなチャンクを追加するだけです。

多くの改善が見られるはずはありませんが、本当に本当に本当にしたいのであれば、MSDNに行き、辞書クラスに追加してください。この種の考え方にはお勧めのクラスですが、PowerShellからそれを使用するのは簡単ではありません。

関連する問題