Câu trả lời:
Bạn có nghĩa là Delegate.Invoke
/ BeginInvoke
hoặc Control.Invoke
/ BeginInvoke
?
Delegate.Invoke
: Thực thi đồng bộ, trên cùng một chủ đề.Delegate.BeginInvoke
: Thực thi không đồng bộ, trên một threadpool
luồng.Control.Invoke
: Thực thi trên luồng UI, nhưng gọi luồng chờ hoàn thành trước khi tiếp tục.Control.BeginInvoke
: Thực thi trên luồng UI và luồng gọi không chờ hoàn thành.Câu trả lời của Tim đề cập đến khi 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 Windows Forms ứng dụng, tôi sẽ đề nghị rằng bạn nên thường sử dụng BeginInvoke
. Bằng cách đó, bạn không cần phải lo lắng về sự bế tắc, chẳng hạn - nhưng bạn cần hiểu rằng UI có thể chưa được cập nhật vào lần tiếp theo bạn nhìn vào nó! Cụ thể, bạn không nên sửa đổi dữ liệu mà luồng UI có thể sắp sử dụng cho mục đích hiển thị. Ví dụ: nếu bạn có một thuộc tính và Person
với , và bạn đã làm:FirstName
LastName
person.FirstName = "Kevin"; // person is a shared reference
person.LastName = "Spacey";
control.BeginInvoke(UpdateName);
person.FirstName = "Keyser";
person.LastName = "Soze";
Sau đó, UI có thể sẽ 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ỳ lạ của mô hình bộ nhớ.)
Trừ khi bạn có loại vấn đề này, tuy nhiên, Control.BeginInvoke
sẽ dễ dàng hơn để xử lý đúng và sẽ tránh chủ đề nền của bạn không phải chờ đợi vì 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 "cháy 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 nên có một cuộc gọi EndXXX tương ứng, thường là trong cuộc gọi lại.
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 quá trình thực thi của nó hoàn thành trước khi chuỗi hiện tại tiếp tục. 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 luồng chờ trên một đại biểu để hoàn thành thực thi, đặc biệt nếu đại biểu đó thực hiện I / O (có thể làm cho ủy nhiệm và khối luồng của bạn).
Trong những trường hợp đó, BeginInvoke sẽ hữu ích. Bằng cách gọi nó, bạn đang nói với đại biểu bắt đầu nhưng sau đó, chủ đề của bạn được tự do làm những việc khác song song với đạ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 năng được cải thiện đáng để phức tạp.
Sự khác biệt giữa Control.Invoke()
và Control.BeginInvoke()
là,
BeginInvoke()
sẽ lên lịch cho hành động không đồng bộ trên luồng GUI. Khi hành động không đồng bộ được lên lịch, mã của bạn sẽ 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 thiInvoke()
sẽ thực thi 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 ủy nhiệm mà bạn vượt qua Invoke()
có thể có các tham số ngoài hoặc giá trị trả về, trong khi một ủy nhiệm bạn chuyển qua BeginInvoke()
không thể (bạn phải sử dụng EndInvoke để lấy kết quả).
Chỉ cần đưa ra một ví dụ ngắn, làm việc để 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 sẽ đồng thời cập nhật văn bản. Nếu sử dụng Gọi , MessageBox sẽ bật sau khi ngủ 3 giây. Do đó, hiển thị hiệu ứng của một cuộc gọi không đồng bộ ( BeginInvoke ) và cuộc gọi ( Gọi ) đồng bộ .
Delegate.BeginInvoke () xếp hàng không đồng bộ cuộc gọi của đại biểu và trả lại quyền điều khiển 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 () gọi đồng bộ đại biểu trong cùng một luồng.
Chỉ cần thêm lý do và thời điểm sử dụng Invoke ().
Cả Invoke () và BeginInvoke () sắp xếp mã bạn chỉ định cho luồng xử lý.
Nhưng không giống như BeginInvoke (), Invoke () giữ chuỗi của bạn cho đến khi bộ đ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 một 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 một đoạn mã hiển thị hộp thoại OK / Hủy. Sau khi người dùng nhấp vào nút và mã sắp xếp của bạn hoàn tất, phương thức invoke () sẽ trở lại và bạn có thể hành động theo phản hồi của người dùng.
Xem Pro WPF trong C # chương 31