2016-03-26 12 views
3

現在、ビルドステップの一環としてTeamCityで使用されるPowerShellスクリプトを作成しています。スクリプトは、にあります。PowerShellスクリプトのファイル読み込みのパフォーマンスが低すぎます

  • 再帰的(GUIDが含まれている)、各ファイルの3行目を読んで、任意の重複があるかどうかを確認
  • 、フォルダ内の特定の拡張子(.item)を持つすべてのファイルをご確認くださいこれらの行では、
  • 私はに完全に新しい午前一つ以上の重複が

を発見された場合はチームシティーのビルドを失敗させる重複GUIDを含むファイルのパスを記録し、GUID自体を記録、

  • PowerS問題がある

    Write-Host "Start checking for Unicorn serialization errors." 
    
    $files = get-childitem "%system.teamcity.build.workingDir%\Sitecore\serialization" -recurse -include *.item | where {! $_.PSIsContainer} | % { $_.FullName } 
    $arrayOfItemIds = @() 
    $NrOfFiles = $files.Length 
    [bool] $FoundDuplicates = 0 
    
    Write-Host "There are $NrOfFiles Unicorn item files to check." 
    
    foreach ($file in $files) 
    { 
        $thirdLineOfFile = (Get-Content $file)[2 .. 2] 
    
        if ($arrayOfItemIds -contains $thirdLineOfFile) 
        { 
         $FoundDuplicates = 1 
         $itemId = $thirdLineOfFile.Split(":")[1].Trim() 
    
         Write-Host "Duplicate item ID found!" 
         Write-Host "Item file path: $file" 
         Write-Host "Detected duplicate ID: $itemId" 
         Write-Host "-------------" 
         Write-Host "" 
        } 
        else 
        { 
         $arrayOfItemIds += $thirdLineOfFile 
        } 
    } 
    
    if ($foundDuplicates) 
    { 
        "##teamcity[buildStatus status='FAILURE' text='One or more duplicate ID's were detected in Sitecore serialised items. Check the build log to see which files and ID's are involved.']" 
        exit 1 
    } 
    
    Write-Host "End script checking for Unicorn serialization errors." 
    

    :それは非常に遅いのです地獄スクリプト、これまでのところ、私はそれが何を期待し、何かを作りました!このスクリプトでチェックする必要があるフォルダには、現在14,000以上の.itemファイルが含まれており、その量は今後も増加する可能性が非常に高いです。私は非常に多くのファイルを開いたり読んだりするのは大規模な作業だと理解していますが、完了までに約30分かかるとは思いませんでした。これは長すぎます。これは、すべての(スナップショット)ビルドのビルド時間が30分長くなることを意味するためです。これは容認できません。私はスクリプトが最大2分で完了することを期待していました。

    私は恐らくこれを行うためのより速いアプローチがないと信じることはできません。この分野のどんな助けも大歓迎です!

    ソリューション

    は、まあ、私は私がこれまでに受信したすべての3つの答えはこの1つで私を助けたことを言わなければなりません。私はまず、.NETフレームワーククラスを直接使用し始めました。次に、辞書を使用して、増加する配列の問題を解決しました。自分のスクリプトを実行するのに要した時間は約30分で、.NETフレームワーククラスを使用することでわずか2分に短縮されました。 Dictionaryソリューションを使用した後も、わずか6〜7秒に短縮されました。私が使用する最終的なスクリプト:

    Write-Host "Start checking for Unicorn serialization errors." 
    
    [String[]] $allFilePaths = [System.IO.Directory]::GetFiles("%system.teamcity.build.workingDir%\Sitecore\serialization", "*.item", "AllDirectories") 
    $IdsProcessed = New-Object 'system.collections.generic.dictionary[string,string]' 
    [bool] $FoundDuplicates = 0 
    $NrOfFiles = $allFilePaths.Length 
    
    Write-Host "There are $NrOfFiles Unicorn item files to check." 
    Write-Host "" 
    
    foreach ($filePath in $allFilePaths) 
    { 
        [System.IO.StreamReader] $sr = [System.IO.File]::OpenText($filePath) 
        $unused1 = $sr.ReadLine() #read the first unused line 
        $unused2 = $sr.ReadLine() #read the second unused line 
        [string]$thirdLineOfFile = $sr.ReadLine() 
        $sr.Close() 
    
        if ($IdsProcessed.ContainsKey($thirdLineOfFile)) 
        { 
         $FoundDuplicates = 1 
         $itemId = $thirdLineOfFile.Split(":")[1].Trim() 
         $otherFileWithSameId = $IdsProcessed[$thirdLineOfFile] 
    
         Write-Host "---------------" 
         Write-Host "Duplicate item ID found!" 
         Write-Host "Detected duplicate ID: $itemId" 
         Write-Host "Item file path 1: $filePath" 
         Write-Host "Item file path 2: $otherFileWithSameId" 
         Write-Host "---------------" 
         Write-Host "" 
        } 
        else 
        { 
         $IdsProcessed.Add($thirdLineOfFile, $filePath) 
        } 
    } 
    
    if ($foundDuplicates) 
    { 
        "##teamcity[buildStatus status='FAILURE' text='One or more duplicate ID|'s were detected in Sitecore serialised items. Check the build log to see which files and ID|'s are involved.']" 
        exit 1 
    } 
    
    Write-Host "End script checking for Unicorn serialization errors. No duplicate ID's were found." 
    

    すべてに感謝します!

  • +0

    ファイルのIO帯域幅はおそらく制限されています。だから、大部分の時間は(おそらく)ディスクからファイルをドラッグするのに使われています。その場合(エンベロープ計算の後ろでそれを確認できるはずです)、それをスピードアップする最も簡単な方法は、SSDのようなより高速なストレージに移行することです。 –

    +0

    @Mike Wise:現代のマシンでは14000個のファイルをコピーするのに30分も過ぎるかもしれませんが、そうかもしれません。私はこの場合、ファイルIOはまったく問題ではないと思います。彼のコードは「ビルドステップの一部」なので、コードが実行される直前にすべてのファイルが処理されたり作成されたりするため、すべてがディスクキャッシュに残っている可能性があります。 –

    答えて

    4

    Get-ChildItemやGet-Contentのような高レベルのコマンドを使用すると、PowerShellが正確に何をするのかは不明です。ですから、私はそれについてもっと明示的になり、.NETフレームワーククラスを直接使用します。

    ではなく、 - コンテンツを取得する各ファイルを開き、最初の3行を読んで使用するよりも、その後

    [String[]] $files = [System.IO.Directory]::GetFiles($folderPath, "*.yourext") 
    

    を使用してフォルダ内のファイルのパスを取得します。これと同じように:私は間違いか2を作ったかもしれ

    [System.IO.StreamReader] $sr = [System.IO.File]::OpenText(path) 
    [String]$line = $sr.ReadLine() 
    while ($line -ne $null) 
    { 
        # do your thing, break when you know enough 
        # ... 
        [String]$line = $sr.ReadLine() 
    } 
    $sr.Close() 
    

    、私は立ち上がってPC上でこれをテストが面倒です。

    また、少ないファイルを使用するようにビルドシステムを再設計することをお勧めします。 14000ファイルと成長は不要です。少数のデータでいくつかのデータを統合することができれば、パフォーマンスが大きく向上する可能性があります。

    重複するGUIDのチェックには、GUID、String>クラスのDictionary <という文字列をファイル名に使用してください。次に、重複が見つかった場合はどこにあるかを報告できます。

    +0

    このスクリプトはSitecoreプロジェクトで使用しています。 Sitecoreを開発するときは、主にC#コードを作成しますが、「開発」の一部はCMSで(つまりデータベース内で)実行する必要があります。このため、データベースはUnicornというツールで自動的にシリアライズされます。 CMSの各「アイテム」をディスク上のシリアル化されたファイルに格納します。そうすれば、すべてのデータベース開発はGitにも格納され、他の開発者に配布しやすくなります。それはかなりうまくいくが、これの欠点は膨大な量のファイルだが、これを行う方法は他にないので、再設計はオプションではない。 – Niles11

    5

    Get-Content[System.IO.File]::ReadLinesに置き換えてください。これがまだ遅すぎる場合は、System.IO.StreamReaderを使用することを検討してください。これにより、少しだけコードを書くことになりますが、最初の3行だけを読むことができます。

    1

    あなたの問題はあなたのArrayによって引き起こされている可能性があり、おそらくファイルの読み込みの問題ではないと思います。

    1. PowerShellで配列のサイズは、あなたが、配列に項目を追加するたびに、それは新しい配列にコピーすべての項目を作成し、不変です。

    2. あなたの配列には値が含まれていないので、配列が大きくなるにつれて$thirdLineOfFileと比較する必要があります。

    私はこの問題を解決するために.Netディクショナリを使用しています。 MSDN Dictionary Reference 注:PowerShellには、スクリプトのどの部分が実際にゆっくり実行されているかを判断するために使用できるコマンドレット「Measure-Command」が用意されています。私はファイルの配列とルックアップの値を増加させる時間と時間を読むことをテストするだろう。ファイルのサイズにもよりますが、実際にはパフォーマンスに問題があるかもしれません。

    .Net辞書を使用するためのコードです。私はあなたの変数の名前を変更しました、それはもはや配列ではないからです。

    Write-Host "Start checking for Unicorn serialization errors." 
    
    $files = get-childitem "%system.teamcity.build.workingDir%\Sitecore\serialization" -recurse -include *.item | where {! $_.PSIsContainer} | % { $_.FullName } 
    #$arrayOfItemIds = @() 
    $IdsProcessed = New-Object 'system.collections.generic.dictionary[string,string]' # A .Net Dictionary will be faster for inserts and lookups. 
    $NrOfFiles = $files.Length 
    [bool] $FoundDuplicates = 0 
    
    Write-Host "There are $NrOfFiles Unicorn item files to check." 
    
    foreach ($file in $files) 
    { 
        $thirdLineOfFile = (Get-Content -path $file -TotalCount 3)[2] # TotalCount param will let us pull in just the beginning of the file. 
    
        #if ($arrayOfItemIds -contains $thirdLineOfFile) 
        if($IdsProcessed.ContainsKey($thirdLineOfFile)) 
        { 
         $FoundDuplicates = 1 
         $itemId = $thirdLineOfFile.Split(":")[1].Trim() 
    
         Write-Host "Duplicate item ID found!" 
         Write-Host "Item file path: $file" 
         Write-Host "Detected duplicate ID: $itemId" 
         Write-Host "-------------" 
         Write-Host "" 
        } 
        else 
        { 
         #$arrayOfItemIds += $thirdLineOfFile 
         $IdsProcessed.Add($thirdLineOfFile,$null) 
        } 
    } 
    
    if ($foundDuplicates) 
    { 
        "##teamcity[buildStatus status='FAILURE' text='One or more duplicate ID's were detected in Sitecore serialised items. Check the build log to see which files and ID's are involved.']" 
        exit 1 
    } 
    
    Write-Host "End script checking for Unicorn serialization errors." 
    
    関連する問題