2010-03-25 50 views
7

Tôi đang tối ưu hóa việc khởi động ứng dụng WinForms. Một vấn đề tôi đã xác định là tải biểu mẫu màn hình giật gân. Mất khoảng nửa giây đến một giây.Cách tăng tốc độ tải màn hình giật gân

Tôi biết rằng đa luồng là không có trên giao diện người dùng, tuy nhiên, nhìn thấy màn hình giật gân là một phần khá tự trị của ứng dụng, có thể bằng cách nào đó giảm thiểu hiệu suất của nó bằng cách ném nó thread (có lẽ trong cách Chrome làm điều đó), để các phần quan trọng của ứng dụng thực sự có thể bắt đầu.

Trả lời

9

.NET framework đã có hỗ trợ rất tốt cho màn hình giật gân trong các ứng dụng Windows Forms. Kiểm tra this thread để biết mẫu mã. Nó thực sự được tối ưu hóa cho thời gian khởi động ấm, nó chắc chắn rằng các chủ đề và màn hình giật gân là lên và chạy trước khi khởi tạo ứng dụng chính.

1

Có.

Bạn cần tạo chuỗi STA mới hiển thị màn hình giật bằng Application.Run, sau đó gọi Close bằng cách sử dụng Invoke sau khi biểu mẫu chính sẵn sàng (trên chuỗi chính).

EDIT: Ví dụ:

static SplashForm splash; 

Thread splashThread = new Thread(delegate() { 
    splash = new SplashForm(); 
    Application.Run(splash);  //Blocking call on separate thread  
}); 
splashThread.SetApartmentState(ApartmentState.STA) 
splashThread.Start(); 

LoadApp(); 

//In MainForm_Shown: 
splash.BeginInvoke(new Action(splash.Close)); 

Đối với hiệu suất tối ưu, bạn nên thực hiện phương pháp Main của bạn hiển thị màn hình giật gân, sau đó gọi một phương thức riêng biệt mà tải các ứng dụng. Bằng cách này, tất cả các hội đồng sẽ được tải sau khi màn hình splash được hiển thị. (Khi bạn gọi một phương thức, JITter sẽ tải tất cả các loại mà nó sử dụng trước khi phương thức bắt đầu thực hiện)

+0

Đó là một cách tiếp cận thú vị. Bạn có thể mở rộng về cách thực sự tạo một Chủ đề STA không. – AngryHacker

+0

Sinh sản sợi chỉ hoạt động không hiệu quả. Mục đích là để giảm thiểu thời gian cần thiết cho màn hình hiển thị, vì vậy tại sao làm chậm nó xuống bằng cách chia sẻ chu kỳ của nó với phần còn lại của quá trình tải ứng dụng? Tốt nhất là dành tất cả mọi thứ để hiển thị giật gân, sau đó tải phần còn lại của ứng dụng. –

+0

@Charles: Nếu bạn hiển thị giật gân trên chủ đề chính, nó sẽ không nhận được bất kỳ tin nhắn nào và sẽ ngừng phản hồi. – SLaks

1

Đa luồng trong WinForms sẽ không sao miễn là tất cả giao diện người dùng vẫn nằm trên một chuỗi.

Đây chỉ là cách màn hình giật gân thường được thực hiện. Công việc quan trọng được thực hiện trên một chủ đề nền, trong khi cửa sổ màn hình splash được hiển thị trên chuỗi giao diện người dùng để cho người dùng biết rằng phần còn lại của chương trình sẽ sớm xuất hiện. Sau khi các công cụ quan trọng đã xảy ra, hãy nâng cao sự kiện để cho chuỗi giao diện người dùng biết rằng đã đến lúc ẩn màn hình giật gân (chỉ cần nhớ sắp xếp trình xử lý sự kiện, sử dụng Invoke(), quay lại chuỗi giao diện người dùng theo thứ tự để đóng màn hình giật gân).

3

Không có gì để đạt được từ việc sinh ra một chuỗi nếu mục tiêu của bạn là để có được màn hình giật gân càng nhanh càng tốt.

Có một số cách để làm màn hình giật gân, và một phức tạp hơn được đề cập here, nhưng đây là một phương pháp dễ dàng Tôi đã sử dụng với thành công trọn vẹn:

Chỉ cần đảm bảo bạn nạp và hiển thị các hình thức giật gân đầu tiên và sau đó tiếp tục tải ứng dụng của bạn trong khi người dùng đang xem màn hình đẹp. Khi mainform được thực hiện tải, nó có thể đóng giật gân ngay trước khi nó cho thấy chính nó (một cách đơn giản để làm điều này là thông qua các hình thức giật gân đến mainform trong constructor của nó):

static void Main() 
{ 
    Application.SetCompatibleTextRenderingDefault(false); 
    SplashForm splash = new SplashForm(); 
    splash.Show(); 
    splash.Refresh(); // make sure the splash draws itself properly 
    Application.EnableVisualStyles(); 
    Application.Run(new MainForm(splash)); 
} 

public partial class MainForm : Form 
{ 
    SplashForm _splash; 
    public MainForm(SplashForm splash) 
    { 
     _splash = splash; 
     InitializeComponent(); 
    } 

    protected override void OnLoad(EventArgs e) 
    { 
     base.OnLoad(e); 

     // or do all expensive loading here (or in the constructor if you prefer) 

     _splash.Close(); 
    } 
} 

Alternative: Nếu bạn không thích để vượt qua giật gân cho MainForm (có thể có vẻ như không thanh nha), sau đó đăng ký sự kiện Load của MainForm, và đóng màn hình splash có:

static class Program 
{ 
    static SplashForm _splash; 

    [STAThread] 
    static void Main() 
    { 
     Application.SetCompatibleTextRenderingDefault(false); 
     _splash = new SplashForm(); 
     _splash.Show(); 
     _splash.Refresh(); 
     Application.EnableVisualStyles(); 
     MainForm mainForm = new MainForm(); 
     mainForm.Load += new EventHandler(mainForm_Load); 
     Application.Run(mainForm); 
    } 

    static void mainForm_Load(object sender, EventArgs e) 
    { 
     _splash.Dispose(); 
    } 
} 

Như đã đề cập trong this thread, nhược điểm tiềm năng để giải pháp này là người dùng sẽ không thể tương tác với màn hình giật gân. Tuy nhiên, điều đó thường không cần thiết.

+0

Nếu bạn hiển thị giật gân trên chủ đề chính, nó sẽ không thể xử lý các tin nhắn Windows và sẽ ngừng phản hồi. – SLaks

+0

Có, và đó có thể là vấn đề nếu ứng dụng mất nhiều thời gian để tải và nhà phát triển muốn người dùng có thể tương tác với màn hình giật trong khi đợi. Nhưng đối với các ứng dụng tải trong thời gian ngắn hợp lý, tương tác với màn hình giật gân thường không được mong muốn. –

+1

Nếu nó tải trong một thời gian ngắn có ít điểm trong việc sử dụng màn hình giật gân. –

1

Câu trả lời thực sự là về nhận thức. Có nhiều phương pháp khác nhau, NGEN một hội đồng, đưa mọi thứ vào GAC, nhưng điều bạn nên hiểu là những gì đang thực sự xảy ra.

C# yêu cầu thời gian để tải máy ảo, tải hội đồng được tham chiếu và lắp ráp tải dựa trên nội dung trên màn hình giật gân đó. Và sau đó nó vẫn mất một lúc từ một "lạnh" bắt đầu để khởi động màn hình đầu tiên.

Điều này là do quá trình biên dịch JIT đang diễn ra khi bạn truy cập lần đầu tiên vào màn hình.

Chiến lược mà tôi sử dụng là trang splash nhẹ truyền thống tải nhanh để hiển thị, nhưng ở chế độ nền, tôi sinh ra một chuỗi và tải biểu mẫu ẩn. Biểu mẫu này có tất cả các điều khiển mà tôi định sử dụng và do đó trình biên dịch JIT đang làm việc của nó và tải các assembly của nó. Điều này cung cấp ảo tưởng về sự phản ứng với một chút bàn tay. Thời gian cần thiết từ khởi chạy + trang splash có thể nhìn thấy + tạm dừng + thời gian để nhấp vào tùy chọn thứ nhất lớn hơn thời gian cần cho luồng để thực thi và sau đó dọn dẹp và dỡ bỏ biểu mẫu.

Nếu không, các ứng dụng sẽ có vẻ phức tạp và chậm đối với người dùng khi khởi động lần đầu tiên. Khởi động ấm màn hình nhanh hơn nhiều vì các hội đồng và JIT đã kết thúc.

1

Chúng tôi làm điều đó bằng cách cung cấp một ứng dụng nhỏ C++ bản địa nhỏ có chức năng như màn hình giật gân.

Nó sau đó sau quá trình này:

  1. tài nhấp chuột kép vào biểu tượng ứng dụng.
  2. Ứng dụng C++ bắt đầu, hiển thị bitmap giật gân như WS_TOPMOST.
  3. Ứng dụng C++ khởi chạy ứng dụng C# chính.
  4. Ứng dụng C# bắt đầu, cuối cùng thông báo cho ứng dụng C++ (thông qua một tệp đơn giản) để thoát.
  5. Ứng dụng C++ thoát.

Ứng dụng C++ cũng có thời gian chờ (trong trường hợp ứng dụng C# bị lỗi) và tự động thoát nếu không được thông báo thoát trong vòng 30 giây.

Cách tiếp cận này có những hạn chế trong thực tế là bạn không thể ghim ứng dụng vào thanh tác vụ. Nếu bạn ghim ứng dụng C++ (là ứng dụng chính cho người dùng cuối), bạn sẽ nhận được một tác vụ khác trên thanh tác vụ, vì ứng dụng C# khác. Tôi nghĩ rằng, tôi có thể giải quyết vấn đề này bằng cách cung cấp các thiết lập trong ứng dụng application manifest của cả ứng dụng C++ và C# để hướng dẫn chúng là ứng dụng "giống nhau" về thanh tác vụ.

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