2016-03-26 26 views
3

Şu anda bir oluşturma adımının bir parçası olarak TeamCity'de kullanılacak bir PowerShell betiği üzerinde çalışıyorum. Herhangi çoğaltmaları olup olmadığınıPowerShell betiği okuma dosyaları performansı çok yavaş

  • yinelemeli
  • (GUID içerir) her dosyanın üçüncü satırını okumak, bir klasör içinde belirli bir uzantıya (.item) ile tüm dosyaları ve check: komut zorundadır bu satırlardaki,
  • bir veya daha fazla çiftleri

bulunursa

  • Ben tamamen yeni duyuyorum TeamCity inşa başarısız kılmak, yinelenen GUID içeren dosyanın yolunu log ve GUID kendisi log 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." 
    

    sorundur: çok yavaş cehennem komut, ama şimdiye kadar ben beklediğiniz bunu yapmak bir şeyi yaptık! Bu betik tarafından kontrol edilmesi gereken klasör şu anda 14.000'den fazla .item dosyası içeriyor ve bu miktarın gelecekte yalnızca artmaya devam etmesi olasıdır. Birçok dosyanın açılmasının ve okunmasının kapsamlı bir işlem olduğunu anlıyorum, ancak bunu tamamlamak için yaklaşık yarım saat sürmesini beklemiyordum. Bu çok uzun, çünkü her (enstantane) yapının yapım süresinin yarım saat kadar uzatılacağı anlamına geliyor, ki bu kabul edilemez. Senaryoyu en fazla birkaç dakika içinde tamamlamayı ummuştum.

    Bunu yapmanın daha hızlı bir yaklaşımı olmadığına inanamıyorum. Bu nedenle bu alandaki herhangi bir yardım büyük beğeni topladı!

    Çözüm

    Eh ben şimdiye kadar alınan tüm 3 cevaplar bunda bana yardımcı oldu söylemek gerekir. İlk olarak .NET framework sınıflarını doğrudan kullanmaya başladım ve daha sonra büyüyen dizi problemini çözmek için sözlüğü de kullandım. Kendi senaryonumu çalıştırmaya harcanan süre yaklaşık 30 dakika oldu, sonra .NET framework sınıflarını kullanarak sadece 2 dakikaya indi. Sözlük çözümünü kullandıktan sonra sadece 6 veya 7 saniyeye indi! Kullandığım son komut dosyası:

    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." 
    

    Herkese teşekkürler!

  • +0

    Muhtemelen burada IO-bant genişliği sınırlıdır. Bu nedenle, büyük miktarda zaman (muhtemelen) diskten dosyaları sürüklemede kullanılıyor. Eğer durum buysa (ve zarf hesabının arkası bunu teyit edebilmelidir), o zaman bunu hızlandırmanın en kolay yolu daha hızlı depolamaya geçmek (SSD gibi) olacaktır. –

    +0

    @Mike Wise: 14000 dosyanın kopyalanması için yarım saat bile herhangi bir modern makinede aşırı olabilirdi. Sanırım bu dosyada IO bir sorun değil. Onun kodu "bir inşa adımının bir parçası" olduğu için, tüm dosyalar kod başlatılmadan hemen önce ele alınacak veya oluşturulacak ve muhtemelen disk önbelleğinde yer alacaktır. –

    cevap

    4

    Get-ChildItem ve Get-Content gibi yüksek düzeyli komutlar kullandığınızda PowerShell'in tam olarak ne yaptığı açık değildir. Bu yüzden bu konuda daha açık olur ve .NET framework sınıflarını doğrudan kullanırdım.

    yerine Get-Content kullanmak yerine, Sonra

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

    kullanarak klasördeki dosyaların yollarını alın her dosyayı açın ve ilk üç satırı okuyun. böylece gibi:

    [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() 
    

    ben bir hata ya da iki yapmış olabilir, ben kalkıp bir PC'de Bunu test tembel değilim.

    Ayrıca, yapı sisteminizi daha az dosya kullanacak şekilde yeniden tasarlamayı düşünebilirsiniz. 14000 dosya ve büyüme gereksiz görünüyor. Bazı verileri daha az dosyada birleştirebilirseniz, performansa da yardımcı olabilir.

    Yinelenen kılavuz denetimleri için, dosya adınız olan dizgi ile bir Sözlük < Guid, String> sınıfı kullanın. Ardından, varsa çiftlerin nerede olduğunu bildirebilirsiniz.

    +0

    Bu komut dosyasını bir Sitecore projesinde kullanıyoruz. Sitecore için geliştirirken temel olarak C# kodu oluşturuyorsunuz, fakat 'geliştirme' nin bazı kısımlarının CMS'de yapılması gerekiyor (yani: bir veritabanında). Bu nedenle, veritabanımız Unicorn adında bir araç tarafından otomatik olarak serileştiriliyor. CMS'deki her 'öğe'yi diskteki serileştirilmiş bir dosyaya kaydeder. Bu şekilde, tüm veritabanı geliştirme Git'de de depolanır ve diğer geliştiricilere dağıtılması kolaydır. Oldukça iyi çalışıyor, ama bunun aşağı doğru büyük miktarda dosya ... ama bunu yapmanın başka bir yolu yoktur, bu yüzden yeniden tasarlama bir seçenek değildir. – Niles11

    5

    'u [System.IO.File]::ReadLines ile değiştirmeyi deneyin. Bunun hala çok yavaş olması durumunda System.IO.StreamReader'u kullanmayı düşünün - bu biraz daha fazla kod yazmanıza neden olur, ancak ilk 3 satırı okumanıza izin verir.

    1

    Sorununuzun Dizinizden kaynaklandığını düşünüyorum ve büyük olasılıkla bir dosya okuma sorunu değil.

    1. PowerShell içinde bir dizinin boyutu böylece diziye bir öğe eklemek her zaman, yeni bir dizi ve kopyalarını tüm öğeleri oluşturur sabittir.

    2. Dizininiz genellikle bu değeri içermiyor ve $thirdLineOfFile ile büyüyen bir dizideki her öğeyi karşılaştırmanız gerekecek.

    Bu sorunu çözmek için Net Sözlükleri kullanıyorum. (Ya da ben birçok tarama yapmıyorum Dizi Listeleri) MSDN Dictionary Reference

    Not: PowerShell aslında yavaş çalışıyor Senaryonuzun hangi kısmının belirlemek için kullanabilirsiniz 'Measure-Command' adlı bir Cmdlet sağlar. Ben dizi ve arama değerleri büyümeye dosya okuma zamanı ve zamanı test ediyorum. Dosyaların boyutuna bağlı olarak, aslında orada da performans sorunları olabilir.

    Kodunuz, .Net Sözlüğü kullanmak üzere uyarlanmıştır. Değişkeninizi yeniden adlandırdım çünkü artık bir dizi değil.

    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."