Masz na myśli Delegate.Invoke
/ BeginInvoke
lub Control.Invoke
/ BeginInvoke
?
Delegate.Invoke
: Wykonuje się synchronicznie w tym samym wątku.
Delegate.BeginInvoke
: Wykonuje się asynchronicznie w threadpool
wątku.
Control.Invoke
: Wykonuje się w wątku interfejsu użytkownika, ale wątek wywołujący czeka na zakończenie przed kontynuowaniem.
Control.BeginInvoke
: Wykonuje się w wątku interfejsu użytkownika, a wywołanie wątku nie czeka na zakończenie.
Odpowiedź Tima wspomina, kiedy możesz chcieć użyć BeginInvoke
- Delegate.BeginInvoke
podejrzewam, że była głównie nastawiona na .
W przypadku aplikacji Windows Forms sugeruję, że zwykle powinieneś używać BeginInvoke
. W ten sposób nie musisz martwić się na przykład o zakleszczenie - ale musisz zrozumieć, że interfejs użytkownika mógł nie zostać zaktualizowany do następnego spojrzenia! W szczególności nie należy modyfikować danych, które wątek interfejsu użytkownika może być używany do celów wyświetlania. Na przykład, jeśli masz Person
z FirstName
i LastName
właściwości, a nie:
person.FirstName = "Kevin"; // person is a shared reference
person.LastName = "Spacey";
control.BeginInvoke(UpdateName);
person.FirstName = "Keyser";
person.LastName = "Soze";
Wtedy interfejs użytkownika może wyświetlać „Keyser Spacey”. (Istnieje szansa z zewnątrz, że może wyświetlić „Kevin Soze”, ale tylko z powodu dziwności modelu pamięci.)
Jeśli nie masz tego rodzaju problemu, Control.BeginInvoke
łatwiej jest rozwiązać problem i uniknąć konieczności oczekiwania przez wątek w tle bez uzasadnionego powodu. Zauważ, że zespół Windows Forms zagwarantował, że możesz używać Control.BeginInvoke
w sposób „odpal i zapomnij” - tj. Bez konieczności dzwonienia EndInvoke
. Nie dotyczy to ogólnie wywołań asynchronicznych: zwykle każde BeginXXX powinno mieć odpowiadające wywołanie EndXXX, zwykle w wywołaniu zwrotnym.
Opierając się na odpowiedzi Jona Skeeta, zdarza się, że chcesz wywołać delegata i poczekać na zakończenie jego wykonywania, zanim bieżący wątek będzie kontynuowany. W takich przypadkach połączenie Invoke jest tym, czego chcesz.
W aplikacjach wielowątkowych możesz nie chcieć, aby wątek czekał na delegata na zakończenie wykonywania, szczególnie jeśli ten delegat wykonuje operacje we / wy (co może spowodować, że delegat i blok wątków).
W takich przypadkach przydatny byłby BeginInvoke. Dzwoniąc do niego, mówisz delegatowi, aby zaczął, ale wtedy twój wątek może robić inne rzeczy równolegle z delegatem.
Korzystanie z BeginInvoke zwiększa złożoność kodu, ale są chwile, kiedy lepsza wydajność jest warta złożoności.
źródło
Różnica między
Control.Invoke()
iControl.BeginInvoke()
jestBeginInvoke()
zaplanuje akcję asynchroniczną w wątku GUI. Po zaplanowaniu akcji asynchronicznej kod jest kontynuowany. Jakiś czas później (nie wiesz dokładnie, kiedy) twoja asynchroniczna akcja zostanie wykonanaInvoke()
wykona akcję asynchroniczną (w wątku GUI) i poczeka, aż akcja się zakończy.Logicznym wnioskiem jest to, że przekazany delegat
Invoke()
może mieć parametry wyjściowe lub wartość zwracaną, podczas gdy przekazany delegat nieBeginInvoke()
może (musisz użyć EndInvoke, aby pobrać wyniki).źródło
Wystarczy podać krótki, działający przykład, aby zobaczyć efekt ich różnicy
Jeśli używasz BeginInvoke , MessageBox wyskakuje jednocześnie z aktualizacją tekstu. Jeśli używasz Invoke , MessageBox wyskakuje po 3 sekundowym śnie. Stąd pokazanie efektu połączenia asynchronicznego ( BeginInvoke ) i synchronicznego ( Invoke ).
źródło
Delegate.BeginInvoke () asynchronicznie kolejkuje wywołanie delegata i natychmiast zwraca kontrolę. Korzystając z Delegate.BeginInvoke (), należy wywołać Delegate.EndInvoke () w metodzie zwrotnej, aby uzyskać wyniki.
Delegate.Invoke () synchronicznie wywołuje delegata w tym samym wątku.
Artykuł MSDN
źródło
Wystarczy dodać, dlaczego i kiedy używać Invoke ().
Zarówno Invoke (), jak i BeginInvoke () zmieniają kod podany w wątku dyspozytora.
Ale w przeciwieństwie do BeginInvoke (), Invoke () wstrzymuje wątek, dopóki dyspozytor nie wykona kodu. Możesz użyć Invoke (), jeśli chcesz zatrzymać operację asynchroniczną, dopóki użytkownik nie dostarczy jakiegoś sprzężenia zwrotnego.
Na przykład możesz wywołać Invoke (), aby uruchomić fragment kodu, który pokazuje okno dialogowe OK / Anuluj. Po kliknięciu przycisku przez użytkownika i zakończeniu działania ustawionego kodu, zostanie zwrócona metoda invoke (), a użytkownik będzie mógł zareagować na odpowiedź użytkownika.
Zobacz Pro WPF w C # rozdział 31
źródło