2012-02-22 41 views
5

Tôi muốn biết nếu có bất kỳ chi phí phát sinh nào thông qua việc sử dụng các phương thức ẩn danh khi tạo một Nhân viên nền.Có bất kỳ chi phí nào trong việc sử dụng các phương thức ẩn danh không?

ví dụ:

public void SomeMethod() 
{ 
    BackgroundWorker worker = new BackgroundWorker(); 
    worker.DoWork += (sender, e) => 
    { 
     //large amount of code 
    } 

    worker.RunWorkerAsync(); 
} 

có ví dụ trên được bất kỳ tốt hơn hoặc tồi tệ hơn định //large amount of code trong một phương pháp riêng biệt?

Có bất kỳ chi phí phát sinh nào trong việc xác định phương thức công nhân nền trong dòng, đặc biệt nếu SomeMethod() được gọi thường xuyên?

+0

Nếu có một số lượng lớn mã bạn có thể muốn tái cấu trúc nó thành một số lượng nhỏ mã gọi các phương pháp khác ... – Chris

Trả lời

4

có một sự khác biệt nhỏ trong cách thức các phương thức được đặt tên và các phương thức anonumous được xử lý khi bạn tạo một delegate từ chúng.

Đại biểu cho các phương thức ẩn danh được lưu trong bộ nhớ cache, vì vậy có một chi phí nhỏ để kiểm tra xem đại biểu đã tồn tại trong bộ nhớ cache chưa. Mặt khác, nếu bạn chạy phương thức nhiều lần, nó sẽ sử dụng lại đại biểu được lưu trong bộ nhớ cache thay vì tạo một phương thức mới.

Đại biểu cho các phương thức được đặt tên không được lưu trong bộ nhớ cache, vì vậy nó sẽ được tạo mỗi lần.

Khác với điều đó không có sự khác biệt. Phương thức anonumous sẽ được tạo tại thời gian biên dịch và tồn tại trong mã giống như một phương thức thông thường, chỉ với một cái tên mà chỉ trình biên dịch biết.

1

Bất cứ khi nào một phương thức ẩn danh (bao gồm lambdas) đóng trên các biến trình biên dịch tạo ra một lớp để giữ các biến này cho bạn. Bất cứ khi nào đại biểu được tạo ra một thể hiện mới của lớp này là quá. Điều này rõ ràng là bổ sung thêm công việc cho thời gian chạy, nhưng nói chung là không đáng kể trong hầu hết các tình huống.

+0

Vì vậy, tôi giả định rằng nếu không có đóng cửa, nó sẽ không tạo ra lớp để nó sẽ không tạo ra bất kỳ sự khác biệt nào? – Chris

+0

@Chris Có, trình biên dịch đủ thông minh để tạo một kiểu ẩn danh (để giữ phương thức nặc danh cộng với các biến được đóng lại) chỉ khi nó được yêu cầu. –

+0

Lớp đóng không được tạo khi bạn tạo đại biểu. Nó được tạo ra trước khi bạn sử dụng địa phương đã đóng kín, bởi vì việc truy cập người dân địa phương trong phương thức "cha mẹ" phải thực sự sử dụng lớp đóng. – svick

0

Tôi đã thử nghiệm tính năng này vào ngày khác (thông qua sử dụng lớp StopWatch). Theo như tôi có thể nói là không có khác biệt đáng kể về hiệu suất giữa cách gọi một phương pháp trực tiếp ...

SomeMethod(); 

... hoặc thông qua một phương pháp vô danh ...

() => SomeMethod(); 
+2

Trình biên dịch sẽ tối ưu hóa sự cần thiết phải tạo một lớp ẩn danh để giữ phương thức ẩn danh vì không có biến nào được đóng lại. –

+0

Thú vị, tôi nghĩ rằng trình biên dịch có thể có một bàn tay trong đó. Hai câu hỏi: nếu phần thân của phương thức nặc danh tham chiếu các biến nằm ngoài phạm vi của nó, điều đó có giới thiệu một chi phí không? Và, nếu như vậy, khi nào mà trên cao sẽ gặp phải? Trong quá trình tạo hoặc thực hiện phương thức nặc danh? – Moonshield

0

Nó chủ yếu ảnh hưởng đến khả năng đọc - một lượng lớn mã ở một nơi gần như không bao giờ tốt ;-)

Xét về hiệu suất thấy When is optimization premature?

2

Trước tiên, có thể bạn không nên đặt nhiều mã vào một phương thức ẩn danh. Nó sẽ dễ đọc hơn nếu bạn tạo ra một phương pháp riêng biệt cho điều đó, hoặc thậm chí tốt hơn, một số phương pháp. Đối với IL được tạo ra, nếu lambda không đóng trên bất kỳ biến nào, thì mã IL được sinh ra giống như khi bạn đặt mã theo phương thức được đặt tên thông thường (ngoại trừ phương thức được tạo ra có tên không rõ ràng). .

Mặt khác, nếu bạn đóng gần một số biến, trình biên dịch sẽ tạo một lớp đóng để giữ biến đó trong một trường. Và truy cập trường là hơi đắt tiền hơn mà truy cập biến cục bộ.

Tóm lại, nếu bạn đóng một số biến, có chi phí nhỏ (bao gồm nhiều đối tượng cần thu gom rác). Trong hầu hết các trường hợp, điều này không quan trọng và đáng lo ngại về điều này sẽ là tối ưu hóa sớm. Nhưng nếu bạn nghĩ rằng nó không quan trọng, bạn nên cấu hình mã.

0

Đây là những gì decompiler nói:

[CompilerGenerated] 
private static DoWorkEventHandler CS$<>9__CachedAnonymousMethodDelegate1; 

[CompilerGenerated] 
private static void <SomeMethod1>b__0(object sender, DoWorkEventArgs e) 
{ 
    throw new NotImplementedException(); 
} 

public void SomeMethod1() 
{ 
    BackgroundWorker worker = new BackgroundWorker(); 
    BackgroundWorker backgroundWorker = worker; 
    backgroundWorker.DoWork += (object sender, DoWorkEventArgs e) => throw new NotImplementedException(); 
    worker.RunWorkerAsync(); 
} 

public void SomeMethod2() 
{ 
    BackgroundWorker worker = new BackgroundWorker(); 
    worker.DoWork += worker_DoWork; 
    worker.RunWorkerAsync(); 
} 

private void worker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    throw new NotImplementedException(); 
} 

Edit:

Nhìn vào mã IL chỉ có chi phí nhỏ trong việc tạo ra/gán phương pháp để ủy thác cho lần đầu tiên.

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