2010-09-09 34 views
5

Tôi đang viết một ứng dụng C# cần có khả năng cho biết cần bao nhiêu thời gian cho một ứng dụng nhất định để mở. Tôi đang sử dụng lớp Đồng hồ bấm giờ làm bộ hẹn giờ của mình. Thời gian bắt đầu thật dễ dàng vì tôi đã cài đặt chính xác cuộc gọi để chạy .exe. Vấn đề là tìm ra cách để thời gian khi chương trình được thực hiện mở. Điều duy nhất tôi có thể nghĩ đến để kiểm tra điều này là sử dụng một đối tượng PerformanceCounter và kiểm tra khi CPU% nhỏ hơn một số nhất định bằng cách sử dụng một vòng lặp while.Làm thế nào để có được thời gian để ứng dụng khởi động?

Hiện tại tôi đang sử dụng PerformanceCounter, nhưng tôi không có may mắn với nó hiển thị CPU% (nó luôn hiển thị 0). Dự đoán của tôi cho điều này là ứng dụng mở ra nhanh hơn PerformanceCounter có thể kiểm tra CPU% hoặc PerformanceCounter không nhìn thấy tên quá trình bởi vì tôi gọi nó quá nhanh (tôi rất nghi ngờ điều này do thực tế là Tôi nghĩ rằng tôi sẽ nhận được lỗi nếu điều này xảy ra).

Có cách nào khác để giải quyết vấn đề này không? Có cái gì tôi có thể làm sai đó là đem lại cho tôi một CPU 0% tất cả các thời gian? Tôi không tìm kiếm các công cụ bên ngoài bên ngoài ứng dụng của mình. Đây là mẫu mã của tôi:

otherApp = new otherApplication.Application(); 
PerformanceCounter cpuCounter = new PerformanceCounter("Process", 
"% Processor Time", "otherApplication"); 
//This next line is to check if PerformanceCounter object is working 
//MessageBox.Show(cpuCounter.NextValue().ToString()); 
stopwatch.Start(); 
while (cpuCounter.NextValue() > 10) 
{ 
} 
stopwatch.Stop(); 

Đã chỉnh sửa: Đã thay đổi mã để nói otherApp vàỨng dụng khác thay vì myApp và myApplication, để dễ hiểu hơn.

Trả lời

2

Bạn nên sử dụng vị trí đã biết trong mã của mình (một phương pháp cụ thể được gọi khi tất cả công việc khởi tạo hoàn tất) thay vì dựa vào việc sử dụng CPU như một phương pháp phỏng đoán.

+0

Tôi cũng đang xem xét điều này. Vì tôi đang sử dụng một cuộc gọi để tạo một cá thể của một ứng dụng thông qua ActiveX, tôi có thể sử dụng một lệnh đơn giản mà chỉ có thể được ứng dụng xử lý khi nó được nạp. Điều đó sẽ cho tôi gần với "thời gian khởi động ứng dụng" như tôi có thể nhận được. – Brundle

+0

Tôi đã kết thúc bằng cách sử dụng thuộc tính từ ứng dụng khác sau cuộc gọi "mới". Sau đó, tôi ngừng bộ hẹn giờ. Bằng cách đó tôi biết rằng việc tạo ra đã hoàn tất. Có, có thể có thêm chút thời gian ở đó do cuộc gọi tài sản, nhưng điều này sẽ không ảnh hưởng đến mục tiêu cuối cùng của tôi. – Brundle

2

Nếu bạn sở hữu mã cho cả ứng dụng của bạn và ứng dụng bạn đang bắt đầu, bạn có thể sử dụng System.Threading.Mutex để liên lạc giữa myApplicationotherApplication. Bằng cách này, otherApplication có thể cho bạn biết khi nào nó đã khởi tạo xong.

3

Nếu ứng dụng của bạn là một ứng dụng cửa sổ, tức là nếu nó là một quá trình với vòng lặp thông báo thì cách tiêu chuẩn sẽ là sử dụng phương pháp Process.WaitForInputIdle.

Phương pháp này sẽ chặn cho đến khi quá trình tương ứng đã đạt trạng thái không hoạt động lần đầu tiên. Đây là trạng thái khi cửa sổ chính của ứng dụng được tạo và bạn có thể gửi tin nhắn đến ứng dụng .

Tên của phương pháp hơi khó hiểu, cần really be called WaitForProcessStartupComplete.

using System; 
using System.Diagnostics; 

class StartupWatch 
{ 
    static void Main() 
    { 
     string application = "calc.exe"; 
     Stopwatch sw = Stopwatch.StartNew(); 
     Process process = Process.Start(application); 
     process.WaitForInputIdle(); 
     Console.WriteLine("Time to start {0}: {1}", application, sw.Elapsed); 
    } 
} 

Lưu ý rằng có thể có khởi tiếp tục xảy ra trong một thread nền đến khi ứng dụng là hoàn toàn sẵn sàng. Tuy nhiên, việc có thể xử lý các thông điệp cửa sổ có lẽ là định nghĩa rõ ràng nhất về một ứng dụng đang được khởi động hoàn toàn.

Cập nhật:

Nếu bạn cần để đo thời gian khởi động của một máy chủ COM bạn vẫn có thể sử dụng Process.Start và sau đó sử dụng AccessibleWindowFromObject để truy cập các đối tượng COM thực tế cho tự động hóa. Quy trình này hơi phức tạp và bạn sẽ cần phải biết tên lớp cửa sổ của đối tượng có thể truy cập.

Dưới đây là ví dụ về cách bạn có thể đo thời gian khởi động của Word và nhận đối tượng Word.Application cùng một lúc, xem các nhận xét về cách bạn sẽ phải điều chỉnh nó cho phù hợp với máy chủ COM của bạn.

using System; 
using System.Diagnostics; 
using System.Reflection; 
using System.Runtime.InteropServices; 
using System.Text; 
using Word = Microsoft.Office.Interop.Word; 

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00020400-0000-0000-C000-000000000046")] 
public interface IDispatch 
{ 
} 

class StartupWatch 
{ 
    [DllImport("user32.dll", SetLastError = true)] 
    static extern IntPtr FindWindow(string lpClassName, string lpWindowName); 

    [DllImport("Oleacc.dll")] 
    static extern int AccessibleObjectFromWindow(IntPtr hwnd, uint dwObjectID, byte[] riid, out IDispatch ptr); 

    public delegate bool EnumChildCallback(IntPtr hwnd, ref IntPtr lParam); 

    [DllImport("User32.dll")] 
    public static extern bool EnumChildWindows(IntPtr hWndParent, EnumChildCallback lpEnumFunc, ref IntPtr lParam); 

    [DllImport("User32.dll")] 
    public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); 

    public static bool EnumChildProc(IntPtr hwndChild, ref IntPtr lParam) 
    { 
     StringBuilder buf = new StringBuilder(128); 
     GetClassName(hwndChild, buf, 128); 
     if (buf.ToString() == "_WwG") 
     { 
      lParam = hwndChild; 
      return false; 
     } 
     return true; 
    } 

    static Word.Application GetWordApplicationObject(Process process) 
    { 
     Word.Application wordApp = null; 
     if (process.MainWindowHandle != IntPtr.Zero) 
     { 
      IntPtr hwndChild = IntPtr.Zero; 

      // Search the accessible child window (it has class name "_WwG") 
      // as described in http://msdn.microsoft.com/en-us/library/dd317978%28VS.85%29.aspx 
      // 
      // adjust this class name inside EnumChildProc accordingly if you are 
      // creating another COM server than Word 
      // 
      EnumChildCallback cb = new EnumChildCallback(EnumChildProc); 
      EnumChildWindows(process.MainWindowHandle, cb, ref hwndChild); 

      if (hwndChild != IntPtr.Zero) 
      { 
       // We call AccessibleObjectFromWindow, passing the constant OBJID_NATIVEOM (defined in winuser.h) 
       // and IID_IDispatch - we want an IDispatch pointer into the native object model. 
       // 
       const uint OBJID_NATIVEOM = 0xFFFFFFF0; 
       Guid IID_IDispatch = new Guid("{00020400-0000-0000-C000-000000000046}"); 
       IDispatch ptr; 

       int hr = AccessibleObjectFromWindow(hwndChild, OBJID_NATIVEOM, IID_IDispatch.ToByteArray(), out ptr); 
       if (hr >= 0) 
       { 
        // possibly adjust the name of the property containing the COM 
        // object accordingly 
        // 
        wordApp = (Word.Application)ptr.GetType().InvokeMember("Application", BindingFlags.GetProperty, null, ptr, null); 
       } 
      } 
     } 
     return wordApp; 
    } 

    static void Main(string[] args) 
    { 
     Stopwatch sw = Stopwatch.StartNew(); 
     Process process = Process.Start(@"C:\Program Files (x86)\Microsoft Office\Office12\WINWORD.EXE"); 
     process.WaitForInputIdle(); 
     Console.WriteLine("Time to start {0}: {1}", "Word", sw.Elapsed); 
     Word.Application wordApp = GetWordApplicationObject(process); 
     Console.WriteLine(string.Format("Word version is: {0}", wordApp.Version)); 
    } 
} 
+0

Tôi đang xem xét điều này vào lúc này. Tôi đang thực sự sử dụng một đối tượng ActiveX để tạo ra thể hiện của ứng dụng, vì vậy tôi không nghĩ Process.Start sẽ làm việc cho tôi. Nhưng nếu có một số cách để sử dụng lớp Process với một tên quy trình từ Windows Task Manager để làm điều này, điều đó sẽ rất thú vị. – Brundle

+1

@Brundle: Sử dụng 'Process.GetProcessById (int processId)' hoặc 'Process.GetProcessesByName (string processName)' bạn có thể nắm giữ một tiến trình bằng cách sử dụng thông tin mà bạn thấy trong Task Manager. Tuy nhiên, điều này sẽ không sử dụng được nếu bạn muốn đo hiệu năng khởi động, đơn giản vì ứng dụng đã được bắt đầu xuất hiện trong Trình quản lý Tác vụ. –

+0

Tôi vừa thử Process.GetProcessesByName (myApplication) với quy trình [0] .WaitForInputIdle() và có vẻ như nó đang hoạt động. Mặc dù tôi có thời gian tương tự khi tôi chỉ lấy hai dòng mã đó ra, nên rất khó để nói. – Brundle

1

Đây là vấn đề Heisenberg kinh điển, bạn ảnh hưởng đến kết quả thử nghiệm bằng phép đo của bạn.

Thời gian khởi động của ứng dụng được quản lý thường bị chi phối bởi thời gian bắt đầu nguội. Thời gian cần thiết bởi hệ thống tập tin để tìm tất cả các hội đồng. Trái ngược với thời gian khởi động ấm, một số nhỏ hơn nhiều bạn nhìn thấy khi các assembly có mặt trong bộ đệm hệ thống tập tin. Sau đó, bạn chỉ thấy lượng thời gian trình biên dịch JIT cần biên dịch mã khởi động của chương trình của bạn. Bài kiểm tra của bạn sẽ luôn luôn là một khởi đầu ấm áp bởi vì chạy mã kiểm thử đặt các assembly .NET vào bộ nhớ cache của hệ thống tập tin. Số hạnh phúc, để chắc chắn, nhưng không chính xác.

Bạn sẽ phải viết bài kiểm tra của mình bằng mã không được quản lý. Một số ngôn ngữ kịch bản mà bạn đã quen thuộc. Hãy giúp nó bằng cách gọi Application.Exit() trong sự kiện được hiển thị của biểu mẫu chính để chương trình của bạn ngay lập tức thoát khi biểu mẫu đầu tiên hiển thị. Bây giờ bạn chỉ cần đo lường quá trình thực hiện trong bao lâu. Có thể đơn giản như tệp .bat trông giống như sau:

time /t 
start /wait yourapp.exe 
time /t 

Khởi động lại máy trước khi bạn chạy thử để bạn có thể chắc chắn rằng GS Heisenberg không có ở đó. Và hãy nhớ rằng con số chính xác mà bạn đo lường sẽ không có khả năng lặp lại trên máy của khách hàng của bạn. Bởi vì nó phụ thuộc vào trạng thái của đĩa cứng. Chỉ sử dụng nó để đo lường sự thành công của các cải tiến gia tăng đối với mã của bạn.

+0

Điểm tốt, nhưng từ mẫu của OP nó cũng có thể là trường hợp 'otherApplication.Application()' dùng để chỉ một máy chủ COM bên ngoài như Word hoặc Excel. –

+0

@ 0xA3 - đúng, đã không xem xét điều đó. Mặc dù vậy, không có nhiều điểm để đo lường, không thể làm cho các chương trình Office nhanh hơn. –

Các vấn đề liên quan