Là chấm tìm nguồn chậm hơn chỉ đọc nội dung tệp?


12

Tôi đã viết một mô-đun PowerShell để lấy các định nghĩa hàm từ các tệp nguồn khác nhau (nghĩa là một tệp .ps1 cho mỗi hàm). Điều này cho phép chúng tôi (như một nhóm) làm việc song song trên các chức năng khác nhau. Mô-đun (tệp .psm1) nhận danh sách các tệp .ps1 có sẵn ...

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

... sau đó lặp qua danh sách và kéo theo từng định nghĩa hàm thông qua nguồn chấm:

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

Vấn đề: Chúng tôi đã nhận thấy rằng tốc độ hoàn thành việc này có thể thay đổi rất nhiều, từ 10 đến 180 giây cho khoảng 50 tệp nguồn, tùy thuộc vào loại máy chúng tôi thử nghiệm. Chúng tôi không thể giải thích sự khác biệt lớn về thời gian và tin rằng chúng tôi đã kiểm soát các biến như loại máy, HĐH, tài khoản người dùng, quyền quản trị viên, hồ sơ PS, phiên bản PS, v.v. Thời gian thực hiện có thể khác nhau trên cùng một máy chủ người dùng từ ngày này sang ngày khác.

Chúng tôi đã tự hỏi nếu đây là một vấn đề với truy cập đĩa và kiểm tra xem chúng tôi có thể đọc từ đĩa nhanh như thế nào. Hóa ra là chạy Get-Content trên tất cả các tệp đó rất nhanh, mà chúng tôi đã tận dụng để giải quyết vấn đề:

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

Tại sao việc thêm các chức năng này thông qua tìm nguồn cung ứng chậm hơn nhiều so với việc đọc và thực thi nội dung tệp?

Câu trả lời:


14

Thiết lập khoa học

Đầu tiên, một số kịch bản để giúp chúng tôi kiểm tra điều này. Điều này tạo ra 2000 tệp script, mỗi tệp có một chức năng nhỏ:

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

Điều đó là đủ để làm cho quá trình khởi động bình thường không quá quan trọng. Bạn có thể thêm nhiều hơn nếu bạn thích. Điều này tải tất cả chúng bằng cách sử dụng nguồn chấm:

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

Điều này tải tất cả chúng bằng cách đọc nội dung của chúng trước:

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

Bây giờ chúng tôi cần thực hiện một số kiểm tra nghiêm túc về cách thức hoạt động của PowerShell. tôi thích JetBrains dotPeek cho một dịch ngược. Nếu bạn đã từng cố gắng nhúng PowerShell trong ứng dụng .NET , bạn sẽ thấy rằng hội đồng bao gồm hầu hết những thứ liên quan là System.Management.Automation. Biên dịch cái đó thành một dự án và PDB.

Để xem tất cả thời gian bí ẩn này đang được sử dụng ở đâu, chúng tôi sẽ sử dụng một hồ sơ. Tôi thích cái được tích hợp trong Visual Studio. Nó rất dễ sử dụng . Thêm thư mục chứa PDB vào các vị trí biểu tượng . Bây giờ, chúng ta có thể thực hiện một chạy hồ sơ của một phiên bản PowerShell chỉ chạy một trong các tập lệnh thử nghiệm. (Đặt tham số dòng lệnh để sử dụng -File với đường dẫn đầy đủ của kịch bản đầu tiên để thử. Đặt vị trí khởi động vào thư mục chứa tất cả các tập lệnh nhỏ.) Sau khi hoàn thành, hãy mở Thuộc tính trên powershell.exe nhập vào mục tiêu và thay đổi các đối số để sử dụng tập lệnh khác. Sau đó bấm chuột phải vào mục trên cùng trong Performance Explorer và chọn Bắt đầu hồ sơ . Trình hồ sơ chạy lại bằng cách sử dụng tập lệnh khác. Bây giờ chúng ta có thể so sánh. Đảm bảo bạn nhấp vào "Hiển thị tất cả mã" nếu được cung cấp tùy chọn; đối với tôi, nó hiển thị trong khu vực Thông báo trong chế độ xem Tóm tắt của Báo cáo hồ sơ mẫu.

Kết quả đến

Trên máy của tôi, Get-Content phiên bản mất 9 giây để đi qua các tệp script 2000. Các chức năng quan trọng trên "Đường dẫn nóng" là:

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

Điều này rất có ý nghĩa: chúng ta phải chờ đợi Get-Content để đọc nội dung từ đĩa và chúng ta phải chờ Invoke-Expression để sử dụng những nội dung đó.

Trên phiên bản nguồn chấm, máy của tôi mất hơn 15 giây để xử lý các tệp đó. Lần này, các chức năng trên Đường dẫn nóng là các phương thức gốc:

WinVerifyTrust
CodeAuthzFullyQualifyFilename

Cái thứ hai ở đó dường như không có giấy tờ, nhưng WinVerifyTrust "thực hiện hành động xác minh lòng tin trên một đối tượng được chỉ định." Điều đó mơ hồ như bạn có thể nhận được, nhưng nói cách khác, hàm đó xác minh tính xác thực của một tài nguyên nhất định bằng cách sử dụng một nhà cung cấp nhất định. Lưu ý rằng tôi chưa kích hoạt bất kỳ nội dung bảo mật ưa thích nào cho PowerShell và chính sách thực thi tập lệnh của tôi là Unrestricted.

Điều đó có nghĩa

Nói tóm lại, bạn đang chờ đợi từng tệp được xác minh theo một cách nào đó, có thể đã kiểm tra chữ ký, mặc dù điều đó không cần thiết khi bạn không hạn chế các tập lệnh được phép chạy. Khi bạn gc và sau đó iex nội dung, giống như bạn đã gõ các chức năng trong bảng điều khiển, vì vậy không có tài nguyên để xác minh.


2
Ben, cảm ơn vì câu trả lời tuyệt vời này. Ấn tượng rằng bạn đã đi xa đến mức biên dịch lại, đó là một bước vượt xa mọi thứ tôi đã thử. Tôi sẽ xem liệu có cách nào tôi có thể làm theo phương pháp thử nghiệm của bạn trên một trong những máy mà vấn đề này nghiêm trọng nhất không. Điều này có thể mất nhiều thời gian vì vậy đừng nín thở!
Charlie Joynt
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.