优化脚本

时间:2014-03-21 06:53:27

标签: powershell

信息

我已经创建了一个脚本,用于分析来自Windows DNS服务器的调试日志。

它执行以下操作:

  1. 使用[System.IO.File] class
  2. 打开调试日志
  3. 在每一行执行正则表达式匹配
  4. 将16个捕获组分隔为自定义对象内的不同属性
  5. 填写词典并附加每个键的值以生成统计信息
  6. 步骤1和2耗时最长。实际上,它们看似无穷无尽的时间,因为文件在读取时会不断增长。

    问题

    由于调试日志的大小(80,000kb),需要很长时间。

    我相信我的代码适用于较小的文本文件,但它无法处理更大的文件。

    代码

    这是我的代码: https://github.com/cetanu/msDnsStats/blob/master/msdnsStats.ps1

    调试日志预览

    这是调试的样子(包括空行)

    将此值乘以 100,000,000 ,然后输入我的调试日志。

    21/03/2014 2:20:03 PM 0D0C PACKET  0000000005FCB280 UDP Rcv 202.90.34.177   3709   Q [1001   D   NOERROR] A      (2)up(13)massrelevance(3)com(0)
    
    21/03/2014 2:20:03 PM 0D0C PACKET  00000000042EB8B0 UDP Rcv 67.215.83.19    097f   Q [0000       NOERROR] CNAME  (15)manchesterunity(3)org(2)au(0)
    
    21/03/2014 2:20:03 PM 0D0C PACKET  0000000003131170 UDP Rcv 62.36.4.166     a504   Q [0001   D   NOERROR] A      (3)ekt(4)user(7)net0319(3)com(0)
    
    21/03/2014 2:20:03 PM 0D0C PACKET  00000000089F1FD0 UDP Rcv 80.10.201.71    3e08   Q [1000       NOERROR] A      (4)dns1(5)offis(3)com(2)au(0)
    

    请求

    我需要关于如何比现在更快地打开和阅读文件的每一行的方法或想法。

    我愿意接受使用其他语言的建议。

2 个答案:

答案 0 :(得分:1)

我会交易这个:

$dnslog = [System.IO.File]::Open("c:\dns.log","Open","Read","ReadWrite")
$dnslog_content = New-Object System.IO.StreamReader($dnslog)


For ($i=0;$i -lt $dnslog.length; $i++)
{


    $line = $dnslog_content.readline()
    if ($line -eq $null) { continue }


    # REGEX MATCH EACH LINE OF LOGFILE
    $pattern = $line | select-string -pattern $regex



    # IGNORE EMPTY MATCH
    if ($pattern -eq $null) {
            continue
    }

为此:

Get-Content 'c:\dns.log' -ReadCount 1000 |
 ForEach-Object {
   foreach ($line in $_)
    {
      if ($line -match $regex)
       {
         #Process matches
       }
    }

这将使文件读取操作的数量减少1000倍。

交易select-string操作需要重新分解其余代码以使用$ matches [n]而不是$ pattern.matches [0] .groups [$ n] .value,但要快得多。 Select-String返回matchinfo对象,其中包含大量有关匹配的附加信息(行号,文件名等),如果需要,这些信息很棒。如果您需要的只是捕获的字符串,那么它就会浪费精力。

您正在创建一个对象($ log),然后将值累积到数组属性中:

$log.date                += @($pattern.matches[0].groups[$n].value); $n++

该阵列的添加会破坏你的表现。此外,哈希表操作比对象属性更新更快。

我首先创建$ log作为哈希表,将键值作为数组列表创建:

$log = @{}
$log.date = New-Object collections.arraylist

然后在你的循环中:

$log.date.add($matches[1]) > $nul)

然后在填充完所有数组列表后,从$ log创建对象。

答案 1 :(得分:0)

作为一般建议,使用Measure-Command找出哪些脚本块占用时间最长。

话虽如此,睡眠过程似乎有点奇怪。如果我没有错误,你会在每行后20毫秒睡觉:

sleep -milliseconds 20

使用20毫秒的日志大小,1亿次迭代,你将获得相当长的总睡眠时间。

在一些不错的批量大小后尝试睡觉。尝试10 000行是好的,

if($i % 10000 -eq 0) {
    write-host -nonewline "."
    start-sleep -milliseconds 20
}