2017-01-20 2 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

좋은 답변입니다. 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에서 배열과 문자열은 모두 변경할 수 없습니다 (내용이 아닌 배열 크기). 배열이나 문자열에 무언가를 추가 할 때마다 시스템은 이전 내용을 새로운 메모리 위치에 복사 한 다음 새 데이터를 추가합니다.

예상되는 최종 크기로 수동으로 배열 크기를 조정하면 배열에서이 문제를 해결할 수 있습니다. 크기 조정은 배열 을 복사하지만 추가 할 때마다가 아니라 한 번 수행합니다. 속도 차이는 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 

3.5 초에 불과 40 밀리 초에서 실행 시간 드롭!

이 기술을 Ansgar의 기술과 결합 할 수 있습니다. 배열의 크기를 조정하고 결과를 크기가 조정 된 배열에 추가 한 다음 끝에 배열을 거대한 문자열에 조인합니다.

일부 의견입니다. 매번 새로운 배열 크기를 지정하여 원하는만큼 크기 조정을 호출 할 수 있습니다. 배열의 Length 속성을 사용하여 현재 배열 크기를 가져올 수 있습니다. 한계에 도달하고 더 많은 공간이 필요하면 크기 조정을 호출하고 다른 큰 덩어리를 추가하십시오.

나는 많은 개선을 보지 않을 것이다. 그러나 정말로 정말로 가능한 한 빨리 가고 싶다면 MSDN에 가서 사전 클래스에 추가를 살펴 봐야한다. 이런 종류의 생각에 권장되는 클래스이지만 PowerShell에서 사용하기 란 쉽지 않습니다.