2008-10-23 42 views
335

Chỉ cần tự hỏi sự khác biệt giữa BeginInvoke()Invoke() là gì?Sự khác biệt giữa Gọi() và BeginInvoke()

Chủ yếu là mỗi thứ sẽ được sử dụng cho.

EDIT: Sự khác nhau giữa việc tạo đối tượng luồng và gọi điện thoại là gì và chỉ cần gọi BeginInvoke() trên một đại biểu? chúng giống nhau hả?

Trả lời

486

Bạn có nghĩa là Delegate.Invoke/BeginInvoke hoặc Control.Invoke/BeginInvoke không?

  • Delegate.Invoke: Thực hiện đồng bộ, trên cùng một chuỗi.
  • Delegate.BeginInvoke: Thực hiện không đồng bộ, trên một chuỗi threadpool.
  • Control.Invoke: Thực hiện trên chuỗi giao diện người dùng, nhưng chuỗi cuộc gọi chờ hoàn thành trước khi tiếp tục.
  • Control.BeginInvoke: Thực hiện trên chuỗi giao diện người dùng và chuỗi cuộc gọi không chờ hoàn thành.

Câu trả lời của Tim đề cập đến khi nào bạn có thể muốn sử dụng BeginInvoke - mặc dù nó chủ yếu hướng đến Delegate.BeginInvoke, tôi nghi ngờ.

Đối với các ứng dụng Windows Forms, tôi khuyên bạn nên thường là sử dụng BeginInvoke. Bằng cách đó bạn không cần phải lo lắng về bế tắc, ví dụ - nhưng bạn cần phải hiểu rằng giao diện người dùng có thể không được cập nhật vào thời điểm bạn xem xét nó lần sau! Cụ thể, bạn không nên sửa đổi dữ liệu mà chuỗi giao diện người dùng có thể sắp sử dụng cho mục đích hiển thị. Ví dụ: nếu bạn có thuộc tính Person with FirstName và LastName và bạn đã làm:

person.FirstName = "Kevin"; // person is a shared reference 
person.LastName = "Spacey"; 
control.BeginInvoke(UpdateName); 
person.FirstName = "Keyser"; 
person.LastName = "Soze"; 

thì giao diện người dùng cuối cùng cũng có thể hiển thị "Keyser Spacey". (Có một cơ hội bên ngoài nó có thể hiển thị "Kevin Soze" nhưng chỉ thông qua sự kỳ quặc của mô hình bộ nhớ.)

Trừ khi bạn có loại vấn đề này, tuy nhiên, Control.BeginInvoke dễ dàng hơn để có được, và sẽ tránh chủ đề nền từ phải chờ đợi không có lý do chính đáng. Lưu ý rằng nhóm Windows Forms đã đảm bảo rằng bạn có thể sử dụng Control.BeginInvoke theo cách "lửa và quên" - tức là không bao giờ gọi EndInvoke. Điều này không đúng với các cuộc gọi không đồng bộ nói chung: thông thường mỗi BeginXXX sẽ có một cuộc gọi EndXXX tương ứng, thường là trong cuộc gọi lại.

+3

Sau đó, tại sao ppl sử dụng Gọi trên BeingInvoke? Không nên có một số lợi thế hơn khi sử dụng Invoke. Cả hai thực thi các quy trình trong nền, chỉ một trong đó là trên cùng một sợi, cái kia trên các luồng khác nhau? – yeeen

+2

@Jon: Trong khi tôi đang sử dụng Dispatcher.BeginInvoke mã của tôi là làm việc tốt và trong Dispatcher.Invoke ứng dụng của tôi làm cho tôi chờ vài giây sau đó nó khởi tạo tất cả các điều khiển sau đó tung ra, Bạn có thể vui lòng giúp tôi để tìm hiểu chính xác ở nơi tôi bị mắc kẹt ? – SharpUrBrain

+0

@All: Ai có thể đưa ra ý tưởng ngắn gọn về Dispatcher.BeginInvoke và Dispatcher.Invoke không? Cách họ làm việc và những gì họ làm, mọi thứ. – SharpUrBrain

8

Delegate.BeginInvoke() xếp hàng không đồng bộ cuộc gọi của đại biểu và trả về quyền kiểm soát ngay lập tức. Khi sử dụng Delegate.BeginInvoke(), bạn nên gọi Delegate.EndInvoke() trong phương thức gọi lại để nhận kết quả.

Delegate.Invoke() đồng bộ gọi đại biểu trong cùng một chuỗi.

MSDN Article

41

Dựa trên câu trả lời của Jon Skeet, có những lúc bạn muốn gọi một đại biểu và chờ đợi để thực hiện nó để hoàn thành trước khi xử lí hiện tại tiếp diễn. Trong những trường hợp đó cuộc gọi Gọi là những gì bạn muốn.

Trong các ứng dụng đa luồng, bạn có thể không muốn một chủ đề đợi đại biểu thực hiện xong, đặc biệt nếu đại biểu đó thực hiện I/O (có thể làm đại biểu và khối chuỗi của bạn).

Trong những trường hợp này BeginInvoke sẽ hữu ích. Bằng cách gọi nó, bạn đang yêu cầu các đại biểu để bắt đầu nhưng sau đó thread của bạn là miễn phí để làm những việc khác song song với các đại biểu.

Sử dụng BeginInvoke làm tăng độ phức tạp của mã của bạn nhưng có những lúc hiệu suất được cải thiện đáng giá tính phức tạp.

21

Sự khác biệt giữa Control.Invoke()Control.BeginInvoke() là,

  • BeginInvoke() sẽ lên kế hoạch hành động không đồng bộ trên thread GUI. Khi hành động không đồng bộ được lên lịch, mã của bạn tiếp tục. Một thời gian sau đó (bạn không biết chính xác khi nào) hành động không đồng bộ của bạn sẽ được thực thi
  • Invoke() sẽ thực hiện hành động không đồng bộ của bạn (trên luồng GUI) và đợi cho đến khi hành động của bạn hoàn tất.

Một kết luận hợp lý là một đại biểu để bạn vượt qua Invoke() có thể có ngoài các thông số hoặc trả lại một giá trị, trong khi một đại biểu để bạn vượt qua BeginInvoke() không thể (bạn phải sử dụng EndInvoke để lấy kết quả).

14

Chỉ cần để cho một đoạn ngắn, làm việc ví dụ để thấy ảnh hưởng của sự khác biệt của họ

new Thread(foo).Start(); 

private void foo() 
{ 
    this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, 
    (ThreadStart)delegate() 
    { 
     myTextBox.Text = "bing"; 
     Thread.Sleep(TimeSpan.FromSeconds(3)); 
    }); 
    MessageBox.Show("done"); 
} 

Nếu sử dụng BeginInvoke, MessageBox bật đồng thời để cập nhật văn bản. Nếu sử dụng Gọi, Hộp thư bật lên sau 3 giây ngủ. Do đó, hiển thị hiệu ứng của một không đồng bộ (BeginInvoke) và cuộc gọi đồng bộ (Gọi).

6

Chỉ cần thêm lý do và thời điểm sử dụng Invoke().

Cả hai Invoke() và BeginInvoke() so sánh mã bạn chỉ định cho chuỗi bộ điều phối.

Nhưng không giống như BeginInvoke(), Invoke() ngăn chặn chuỗi của bạn cho đến khi người điều phối thực thi mã của bạn. Bạn có thể muốn sử dụng Invoke() nếu bạn cần tạm dừng hoạt động không đồng bộ cho đến khi người dùng đã cung cấp một số loại phản hồi.

Ví dụ: bạn có thể gọi Invoke() để chạy đoạn mã hiển thị hộp thoại OK/Hủy. Sau khi người dùng nhấp vào một nút và mã marshaled của bạn hoàn thành, phương thức invoke() sẽ trả về và bạn có thể hành động dựa trên phản hồi của người dùng.

Xem Pro WPF trong C# chương 31

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