2010-05-12 24 views
10

Trong một hình thức, so sánhSự khác biệt giữa Gọi và BeginInvoking một MessageBox là gì?

BeginInvoke (new Action (() => { 
    MessageBox.Show()); 
})); 

với

Invoke (new Action (() => { 
    MessageBox.Show()); 
})); 

sự khác biệt là gì, và khi nào tôi nên sử dụng một trong khác không? Làm thế nào là hành vi bị ảnh hưởng bởi các máy bơm tin nhắn của MessageBox?

Tôi đã thực hiện một số thử nghiệm và thấy rằng cả hai phương thức đều chặn giao diện người dùng.

Sự khác biệt duy nhất là Invoke thực sự được gọi ngay lập tức trong khi BeginInvoke mất một thời gian (rất ngắn) cho đến khi mã được chạy. Điều này là để được mong đợi.

+0

Đối với tất cả người trả lời: Xin lỗi, đã hết phiếu bầu tại thời điểm này, sẽ chuyển lên vào ngày mai :) – mafu

Trả lời

15

BeginInvoke sẽ gọi đại biểu không đồng bộ, quay trở lại ngay lập tức đã xếp hàng đợi đại biểu để thực thi độc lập với chuỗi hiện tại.

Invoke sẽ gọi đại biểu đồng bộ, chặn chuỗi cuộc gọi cho đến khi người được ủy quyền hoàn tất.

Để thấy sự khác biệt, hãy thử đoạn mã sau:

BeginInvoke(new Action(()=>Console.WriteLine("BeginInvoke"))); 
Console.WriteLine("AfterBeginInvokeCalled"); 

Invoke(new Action(()=>Console.WriteLine("Invoke"))); 
Console.WriteLine("AfterInvokeCalled"); 

Bạn sẽ thấy kết quả tương tự như sau, nơi mà các "BeginInvoke" text chậm do thực hiện không đồng bộ của nó:

AfterBeginInvokeCalled
Gọi
AfterInvokeCalled
BeginInvoke

Về hành vi bạn quan sát, vì đó chỉ là hành động gọi đại biểu đồng bộ hoặc không đồng bộ; nội dung của phương pháp cũng có thể khiến cho chuỗi cuộc gọi ngừng hoặc giao diện người dùng bị chặn. Trong trường hợp hiển thị hộp thư, bất kể ủy nhiệm có bị trì hoãn sử dụng BeginInvoke hay không, khi ủy nhiệm được gọi, giao diện người dùng sẽ bị chặn cho đến khi hộp thư bị loại bỏ.

3

BeginInvoke là không đồng bộ ... điều này có nghĩa là chuỗi cuộc gọi sẽ không chờ phương thức được gọi trở lại.

OK, hộp thoại luôn đóng băng GUI. Nhưng sự khác biệt giữa bắt đầu gọi và gọi nên được rõ ràng:

Gọi đợi cho phương thức được gọi là trả về BeginInvoke thì không.

+0

Tôi không đồng ý. Xem câu hỏi đã chỉnh sửa. --- Edit: Ah, vâng, nhưng MessageBoxes không phải luôn luôn là phương thức? – mafu

+0

@mafutcrt: Tôi nghĩ bạn nhầm lẫn hai điều. MessageBox sẽ vẫn chặn giao diện người dùng, nhưng hành động thực tế gọi phương thức lambda là không đồng bộ khi được gọi qua BeginInvoke. Chỉ vì cuộc gọi đó không đồng bộ không có nghĩa là kết quả của cuộc gọi sẽ là. –

+0

@ Jeff: Vâng, đó là sự thật. Tôi đề nghị @Simon bao gồm giải thích này trong câu trả lời của mình để làm cho nó rõ ràng hơn. – mafu

1

Đối với MessageBox.Show, câu hỏi hầu như không liên quan.

Sự khác biệt chỉ là với BeginInvoke, các gọi chủ đề bản thân sẽ không chặn, vì vậy nó có thể tiếp tục điều làm (dọn dẹp, tiếp tục xử lý, vv).

Chuỗi giao diện người dùng rõ ràng sẽ chặn, bởi vì có một cửa sổ phương thức xuất hiện chờ đầu vào của người dùng để đóng.

14

Simon thực sự không sai.

BeginInvoke cũng giống như gửi thư tới chuỗi giao diện người dùng và nói "Làm điều này ngay khi bạn có cơ hội".

Invoke giống như nói "Làm điều này ngay bây giờ. Tôi sẽ đợi."

Làm rõ: chỉ vì bạn nói thread UI, "Hãy làm điều này ngay bây giờ," đó không có nghĩa bạn là God of thread UI và có thể buộc nó phải thả tất cả những gì nó đang làm. Về cơ bản, các từ khóa trong câu nói trên là "Tôi sẽ đợi."

Điều này, trong mã mẫu của bạn, thông báo bạn đang gửi đến chuỗi giao diện người dùng là: gọi MessageBox.Show. Đoán cái gì? Điều đó sẽ chặn chuỗi giao diện người dùng theo cách.

Nếu bạn muốn nhận thấy hành vi không đồng bộ của BeginInvoke, hãy gọi nó từ một chuỗi riêng biệt, đặt điểm ngắt sau lệnh gọi BeginInvoke trong mã của bạn và nhận thấy điểm ngắt được nhấn ngay cả khi hộp thông báo được hiển thị (và Giao diện người dùng bị chặn). Nếu bạn gọi số Invoke, mã sẽ không tiếp tục cho đến khi người dùng loại bỏ hộp thư.

+1

Đó là một lời giải thích mà tôi đang tìm kiếm :) – mafu

+1

Giải thích tốt. Chỉ cần lưu ý rằng cả hai BeginInvoke và Invoke đều nói "Làm điều này ngay sau khi bạn có cơ hội.", Nhưng Invoke cũng cho biết thêm "Và tôi sẽ đợi cho đến khi bạn hoàn tất." Gọi là không thể vội vàng mọi thứ cùng, như bạn đề nghị ("Làm điều này ngay bây giờ"). –

+0

@ Allon: Vâng, tôi đoán đó là loại chủ quan cách bạn diễn giải những từ đó. Điều này là, trong cuộc sống * thực *, bạn * cũng * không thể ** làm ** ai đó làm điều gì đó ** ngay bây giờ ** - nhưng bạn có thể * bảo * họ làm điều đó "ngay bây giờ" và đứng đó với khoanh tay của bạn, khai thác bàn chân của bạn cho đến khi họ đã thực sự thực hiện nó. Đối với tôi, đây là mục đích của 'Gọi '- bạn nói đúng là nó không giống như bạn có thể buộc nó hủy bỏ bất kỳ mã nào mà nó hiện đang thực hiện; nhưng bạn có hiệu quả * nói *, ít nhất, "Làm điều này ngay bây giờ." –

2

Trong khi hầu hết các câu trả lời đều đúng về mặt kỹ thuật, chúng không hỏi câu hỏi rõ ràng.

Tại sao bạn muốn gói các cuộc gọi MessageBox() của bạn trong Invoke/BeginOnvoke ngay từ đầu?

Chỉ đơn giản là không có lợi ích khi sử dụng BeginInvoke hoặc Gọi trong tình huống này, như Jeff đã giải thích. Có vẻ như bạn đang bối rối giữa việc sử dụng Invoke/BeginInvoke trên một cửa sổ hình thức/điều khiển trong một tình huống đa luồng, và sử dụng Invoke/BeginInvoke trên một ví dụ đại biểu (tức là mô hình lập trình Asynchornous).

Điều này dễ thực hiện vì các tên rõ ràng giống hệt nhau, tuy nhiên các tình huống bạn sẽ sử dụng chúng và hành vi của chúng khác nhau.

Sách CLR Via C# đưa ra giải thích tốt về cả hai loại Invoke/BeginInvoke.

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