Nokta kaynağı yalnızca dosya içeriğini okumaktan daha mı yavaş?


13

Farklı kaynak dosyalarından işlev tanımlarını (yani işlev başına bir .ps1 dosyası) çeken bir PowerShell modülü yazdım. Bu bize (ekip olarak) paralel olarak farklı fonksiyonlar üzerinde çalışmamızı sağlar. Modül (.psm1 dosyası) kullanılabilir .ps1 dosyalarının listesini alır ...

$Functions = Get-ChildItem -Path $FunctionPath *.ps1

... daha sonra listede dolaşır ve nokta kaynağı ile her bir işlev tanımını çeker:

foreach($Function in $Functions) {
  . $Function.Fullname                                     # Can be slow
}

Sorun: Test ettiğimiz makineye bağlı olarak, bunun tamamlanma hızının yaklaşık 50 kaynak dosyası için 10 ila 180 saniye arasında çok değişebileceğini fark ettik. Alınan zamandaki geniş çeşitliliği açıklayamayız ve makine tipi, işletim sistemi, kullanıcı hesabı, yönetici izinleri, PS profili, PS sürümü vb. Değişkenler için kontrol ettiğimize inanıyoruz. Alınan zaman aynı ana bilgisayarda aynı için değişebilir kullanıcı bir günden diğerine.

Bunun disk erişimi ile ilgili bir sorun olup olmadığını merak ettik ve diskten ne kadar hızlı okuyabileceğimizi test ettik. Get-ContentTüm bu dosyalar üzerinde çalışmanın çok hızlı olduğu ortaya çıktı, bu da soruna geçici bir çözümden yararlandık:

foreach($Function in $Functions) {
  Invoke-Expression (Get-Content $Function.Fullname -Raw)  # Is quick
}

Neden bu işlevleri nokta kaynaklı olarak eklemek, dosya içeriğini okumak ve yürütmekten daha yavaştır?

Yanıtlar:


17

Bilim Kurmak

İlk olarak, bunu test etmemize yardımcı olacak bazı komut dosyaları. Bu, her biri tek bir küçük işleve sahip 2000 komut dosyası oluşturur:

1..2000 | % { "Function Test$_(`$someArg) { Return `$someArg * $_ }" > "test$_.ps1" }

Bu, normal başlatma yükünü çok fazla önemli değil yapmak için yeterli olmalıdır. İsterseniz daha fazlasını ekleyebilirsiniz. Bu, nokta kaynağı kullanarak hepsini yükler:

dir test*.ps1 | % {. $_.FullName}

Bu, önce içeriğini okuyarak hepsini yükler:

dir test*.ps1 | % {iex (gc $_.FullName -Raw)}

Şimdi PowerShell'in nasıl çalıştığına dair ciddi bir inceleme yapmamız gerekiyor. Bir decompiler için JetBrains dotPeek seviyorum . PowerShell'i bir .NET uygulamasına gömmeyi denediyseniz , ilgili öğelerin çoğunu içeren derlemenin olduğunu görürsünüz System.Management.Automation. Bunu bir projeye ve bir PDB'ye dönüştürün.

Tüm bu gizemli zamanın nerede harcandığını görmek için bir profiler kullanacağız. Visual Studio'da yerleşik olanı beğendim. Kullanımı çok kolay . PDB'yi içeren klasörü sembol konumlarına ekleyin . Şimdi, yalnızca test komut dosyalarından birini çalıştıran bir PowerShell örneğinin profil oluşturma işlemini yapabiliriz. (Denenecek -Fileilk komut dosyasının tam yolu ile kullanılacak komut satırı parametrelerini ayarlayın. Başlangıç ​​konumunu tüm küçük komut dosyalarını içeren klasöre ayarlayın.) Bu işlem yapıldıktan sonra, powershell.exeHedefler altındaki girişteki Özellikler'i açın ve değiştirin. diğer komut dosyasını kullanmak için argümanlar. Ardından, Performans Gezgini'nde en üstteki öğeyi sağ tıklayın ve Profil Oluşturmaya Başla'yı seçin. Profil oluşturucu diğer komut dosyasını kullanarak yeniden çalışır. Şimdi kıyaslayabiliriz. Seçenek sunulursa "Tüm Kodu Göster" i tıkladığınızdan emin olun; benim için, bu, Örnek Profil Oluşturma Raporunun Özet görünümünde bir Bildirimler alanında görünür.

Sonuçlar gelir

Makinemde, Get-Contentsürümün 2000 komut dosyalarından geçmesi 9 saniye sürdü. "Sıcak Yol" daki önemli fonksiyonlar:

Microsoft.PowerShell.Commands.GetContentCommand.ProcessRecord
Microsoft.PowerShell.Commands.InvokeExpressionCommand.ProcessRecord

Bu çok mantıklı: Get-Contentiçeriği diskten okumak için beklememiz Invoke-Expressionve bu içerikleri kullanmak için beklememiz gerekiyor.

Nokta kaynağı sürümünde, makinem bu dosyalar üzerinde çalışmak için 15 saniyeden biraz fazla zaman harcadı. Bu sefer, Hot Path'daki işlevler yerel yöntemlerdi:

WinVerifyTrust
CodeAuthzFullyQualifyFilename

İkincisi belgelenmemiş gibi görünüyor, ancak WinVerifyTrust"belirtilen nesne üzerinde bir güven doğrulama eylemi gerçekleştiriyor." Bu, elde edebileceğiniz kadar belirsizdir, ancak başka bir deyişle, bu işlev, belirli bir kaynağın belirli bir sağlayıcıyı kullanarak gerçekliğini doğrular. PowerShell için herhangi bir fantezi güvenlik öğesini etkinleştirmediğimi ve komut dosyası yürütme politikamın olduğunu unutmayın Unrestricted.

Bu ne demek

Kısacası, çalıştırılmasına izin verilen komut dosyalarını kısıtlamasanız bile, her dosyanın bir şekilde doğrulanmasını, muhtemelen bir imza olup olmadığını kontrol etmeyi bekliyorsunuz. Siz gcve daha iexsonra içindekiler, konsoldaki işlevleri yazmışsınızdır, bu nedenle doğrulanacak kaynak yoktur.


2
Ben, bu mükemmel cevap için teşekkürler. Derlemenin ötesine geçtiğinizden etkilendim, bu da denediğim her şeyin ötesinde bir adım. Bu sorunun en akut olduğu makinelerden birinde test yönteminizi takip edebilmemin bir yolu olup olmadığını göreceğim. Bu biraz zaman alabilir, bu yüzden nefesinizi tutmayın!
Charlie Joynt
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.