2009-11-23 30 views
6

Trong ứng dụng tôi đang phát triển, chúng tôi sử dụng điều khiển DevExpress XtraGrid, có sự kiện RowCellStyle cho phép tùy chỉnh kiểu của mỗi ô. Xử lý sự kiện cho sự kiện này thường trông giống như rằng:Chi phí tạo đối tượng Phông chữ trong .NET

private gridView1_RowCellStyle(object sender, RowCellStyleEventArgs e) 
{ 
    if (/* Some condition */) 
    { 
     e.Appearance.Font = new Font(gridView1.Appearance.Font, FontStyle.Bold); 
    } 
} 

xử lý này được gọi mỗi khi một tế bào được trả lại, vì vậy nó có thể tạo ra một số lượng lớn các Font trường. Vì vậy, tôi tự hỏi về chi phí làm điều đó ... Tôi đã làm một vài thí nghiệm, và có vẻ như là một xử lý HFONT mới được tạo ra mỗi lần. Tôi có nên lo lắng về nó? Tác động của việc sử dụng tài nguyên đến mức nào?

Nếu nó có tác động hiệu suất đáng kể, không nên có lớp học FontCache hoặc tương tự?

Lưu ý: Tôi biết làm thế nào để giải quyết vấn đề (tôi chỉ cần tạo phông chữ một lần và tái sử dụng nó mỗi thời gian), câu hỏi của tôi thực sự là về chi phí của việc tạo ra nhiều HFONT xử lý

+1

Tôi vô tình có mã như vậy trong vòng lặp kết xuất trò chơi một lần. Tôi nghĩ rằng nó đã giảm FPS từ> 200 xuống dưới 40. – Jimmy

+0

Tối ưu hóa sớm là gốc rễ của mọi điều ác -____-. –

+6

Việc sa thải sớm các mối quan tâm về hiệu suất là một điều xấu xa ít nổi tiếng hơn. – Jimmy

Trả lời

6

thử nghiệm nó; Tôi nhận được về hiệu suất tăng gấp đôi vào tái sử dụng (trong phiên bản, tái sử dụng = 3000 ms, tái tạo = 4900ms)

using System.Windows.Forms; 
using System.Drawing; 
using System.Diagnostics; 
static class Program 
{ 
    static void Main() 
    { 
     Button btn1, btn2; 
     Form form = new Form 
     { 
      Controls = { 
       (btn1 = new Button { Dock = DockStyle.Bottom, Text = "reuse" }), 
       (btn2 = new Button { Dock = DockStyle.Bottom, Text = "recreate"}) 
      } 
     }; 
     btn1.Click += delegate 
     { 
      var watch = Stopwatch.StartNew(); 
      using (var gfx = form.CreateGraphics()) 
      using (var font = new Font(SystemFonts.DefaultFont, FontStyle.Bold)) 
      {     
       gfx.Clear(SystemColors.Control); 
       for (int i = 0; i < 10000; i++) 
       { 
        gfx.DrawString("abc", font, SystemBrushes.ControlText, i % 103, i % 152); 
       } 
      } 
      watch.Stop(); 
      form.Text = watch.ElapsedMilliseconds + "ms"; 
     }; 
     btn2.Click += delegate 
     { 
      var watch = Stopwatch.StartNew(); 
      using (var gfx = form.CreateGraphics()) 
      { 
       gfx.Clear(SystemColors.Control); 
       for (int i = 0; i < 10000; i++) 
       { 
        using (var font = new Font(SystemFonts.DefaultFont, FontStyle.Bold)) 
        { 
         gfx.DrawString("abc", font, SystemBrushes.ControlText, i % 103, i % 152); 
        } 
       } 
      } 
      watch.Stop(); 
      form.Text = watch.ElapsedMilliseconds + "ms"; 
     }; 
     Application.Run(form); 

    } 
} 
+1

Đối số khá thuyết phục ... cảm ơn! Có cơ chế bộ nhớ đệm phông chữ hiện có nào trong .NET không? Tôi không thể tìm thấy bất cứ điều gì như thế trong System.Drawing ... –

2

Font thực hiện IDisposable - bạn nên chắc chắn rằng bạn gọi Dispose khi bạn đã hoàn thành với nó.

Đây là tài nguyên không được quản lý để có thể hệ điều hành cuối cùng sẽ hết tài nguyên để giúp bạn có nhiều đối tượng hơn.

Kiểm tra số lượng xử lý GDI trong TaskManager để xem nó có tiếp tục tăng hay không.

+0

Ngoài ra, nếu bạn đang sử dụng Font đó nhiều, hãy làm nó một lần và sử dụng lại nó! Không cần phải liên tục instanciate nó. –

+0

@Sonny Boy - xem câu hỏi:> Lưu ý: Tôi biết cách giải quyết vấn đề (Tôi chỉ cần tạo phông chữ một lần và tái sử dụng nó mỗi lần), câu hỏi của tôi thực sự là về chi phí tạo nhiều tay cầm HFONT –

2

Tái sử dụng hầu như luôn nhanh hơn theo yêu cầu, nhưng khả năng sử dụng lại hoặc bộ nhớ cache Các đối tượng phông chữ có thể thay đổi.

Nếu bạn đang sử dụng lại các đối tượng Phông chữ và liên kết các đối tượng Phông chữ riêng biệt với mọi điều khiển, bạn sẽ tăng cơ hội vượt quá giới hạn xử lý gdi. Điều này sẽ gây hại cho tất cả các ứng dụng đang được sử dụng bởi một người dùng nhất định khi nó xảy ra.

Lý tưởng nhất là bạn nên lưu bộ nhớ cache đối tượng Phông chữ ở cấp ứng dụng/quy trình và chỉ bộ tối thiểu cần thiết (có thể là tối đa một tá hoặc nhiều nhất). Ngoài ra, việc lưu vào bộ nhớ cache một bộ phông chữ được chia sẻ nhỏ và các đối tượng GDI khác cho phép bạn thực hiện tốt hơn việc xử lý các thư phức tạp như WM_SETTINGCHANGE. Trong mẫu của bạn, bạn đang sửa đổi các giá trị mặc định và bạn có thể gặp lỗi khi người dùng thay đổi lược đồ hoặc phông chữ hiển thị mặc định trong cửa sổ. Trong WM_SETTINGCHANGE, bạn sẽ cân nhắc việc phát hành các bản sao được lưu trong bộ nhớ cache và khởi tạo hoặc chuẩn bị các bộ phông chữ mới.

WM_SETTINGCHANGE (Windows) @ MSDN

Nếu bạn có nhu cầu có hàng trăm phông chữ khác nhau (hoặc đối tượng GDI khác) có sẵn, bạn nên phông chữ không bộ nhớ cache và chỉ tạo ra những gì bạn cần theo yêu cầu. Đây không phải là hiệu suất thân thiện, nhưng nó sẽ giúp ứng dụng của bạn cùng tồn tại với các ứng dụng khác mà người dùng có thể đã mở. Việc giữ hàng trăm đối tượng GDI sẽ làm tăng khả năng của người dùng gặp phải giới hạn xử lý GDI. Tuy nhiên, bộ nhớ cache dựa trên tham chiếu có thể cung cấp sự cân bằng ở đây phù hợp nhất với bạn, giữ bản sao cứng chỉ các biến thể được sử dụng thường xuyên nhất.

Cuối cùng, như đã đề cập bởi Matt Breckon, hãy sử dụng IDisposable cho tất cả các đối tượng GDI có sẵn. Điều này sẽ giúp bạn tránh rò rỉ xử lý gdi.

+0

+1 , điểm tốt về WM_SETTINGCHANGE nếu tôi triển khai cơ chế bộ nhớ cache ... –

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