Qual è la differenza tra Invoke () e BeginInvoke ()


398

Ti stai solo chiedendo quale sia la differenza tra BeginInvoke()e Invoke()?

Principalmente per cosa sarebbe usato ciascuno.

EDIT: Qual è la differenza tra la creazione di un oggetto threading e la chiamata invoke su quello e la semplice chiamata BeginInvoke()a un delegato? O sono la stessa cosa?

Risposte:


568

Intendi Delegate.Invoke/ BeginInvokeo Control.Invoke/ BeginInvoke?

  • Delegate.Invoke: Viene eseguito in modo sincrono, sullo stesso thread.
  • Delegate.BeginInvoke: Viene eseguito in modo asincrono, su un threadpoolthread.
  • Control.Invoke: Viene eseguito sul thread dell'interfaccia utente, ma il thread chiamante attende il completamento prima di continuare.
  • Control.BeginInvoke: Viene eseguito sul thread dell'interfaccia utente e il thread chiamante non attende il completamento.

La risposta di Tim menziona quando potresti voler usare BeginInvoke- anche se era principalmente orientato verso Delegate.BeginInvoke, sospetto.

Per le app di Windows Form, suggerirei di utilizzare di solitoBeginInvoke . In questo modo, ad esempio, non è necessario preoccuparsi del deadlock, ma è necessario comprendere che l'interfaccia utente potrebbe non essere stata aggiornata al prossimo sguardo! In particolare, non è necessario modificare i dati che il thread dell'interfaccia utente potrebbe essere in uso per scopi di visualizzazione. Ad esempio, se hai un Personwith FirstNamee LastNameproprietà e hai fatto:

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

Quindi l'interfaccia utente potrebbe finire con la visualizzazione di "Keyser Spacey". (C'è una possibilità esterna che potrebbe visualizzare "Kevin Soze" ma solo attraverso la stranezza del modello di memoria.)

A meno che tu non abbia questo tipo di problema, tuttavia, Control.BeginInvokeè più facile ottenere il giusto, ed eviterà che il tuo thread in background non debba attendere senza una buona ragione. Si noti che il team di Windows Form ha garantito che è possibile utilizzare Control.BeginInvokein modo "ignora e dimentica", ovvero senza mai chiamare EndInvoke. Questo non è vero per le chiamate asincrone in generale: normalmente ogni BeginXXX dovrebbe avere una chiamata EndXXX corrispondente, di solito nella richiamata.


4
Allora perché ppl dovrebbe usare Invoke over BeingInvoke? Non dovrebbero esserci alcuni vantaggi rispetto all'uso di Invoke. Entrambi eseguono processi in background, solo che uno si trova sullo stesso thread, l'altro su thread diversi?
yeeen

2
@Jon: Mentre sto usando Dispatcher.BeginInvoke il mio codice funziona bene e in Dispatcher.Invoca la mia applicazione facendomi aspettare qualche secondo quindi inizializza tutti i controlli e poi il lancio, puoi per favore aiutarmi a scoprire esattamente in quale posto mi sono bloccato ?
SharpUrBrain

6
@SharpUrBrain: Control.BeginInvoke è una specie di equivalente di Dispatcher.BeginInvoke, ma per WinForms (mentre Dispatcher è per WPF e Silverlight).
Jon Skeet,

4
@SharpUrBrain: suggerirei di porre una domanda specifica piuttosto che continuare nei commenti e, naturalmente, verificare se la stessa domanda è già stata posta da qualcun altro prima.
Jon Skeet,

2
@AZ: Sì, per "sul thread dell'interfaccia utente" intende sul particolare "thread dell'interfaccia utente" che possiede l'handle di quel particolare controllo. In genere, esiste un solo thread dell'interfaccia utente, ma è possibile avere più thread dell'interfaccia utente e nelle applicazioni avanzate ci sono ragioni per cui li vorresti. Tecnicamente, qualsiasi thread (normale?) Potrebbe avviare un pump dei messaggi dell'interfaccia utente e diventare un thread dell'interfaccia utente - e in seguito potrebbe arrestare il pump dei messaggi e non essere più un thread dell'interfaccia utente. (Presumo che non sia qualcosa da provare su un thread di thread pool, però.)
Rob Parker,

46

Sulla base della risposta di Jon Skeet, ci sono momenti in cui si desidera invocare un delegato e attendere il completamento della sua esecuzione prima che il thread corrente continui. In questi casi la chiamata Invoke è ciò che desideri.

Nelle applicazioni multi-threading, potrebbe non essere necessario attendere che un thread attenda che un delegato termini l'esecuzione, soprattutto se quel delegato esegue I / O (che potrebbe rendere il delegato e il blocco thread).

In quei casi, BeginInvoke sarebbe utile. Chiamandolo, stai dicendo al delegato di iniziare, ma poi il tuo thread è libero di fare altre cose in parallelo con il delegato.

L'uso di BeginInvoke aumenta la complessità del codice ma ci sono momenti in cui le prestazioni migliorate valgono la complessità.


27

La differenza tra Control.Invoke()e Control.BeginInvoke()è,

  • BeginInvoke()pianificherà l'azione asincrona sul thread della GUI. Quando viene pianificata l'azione asincrona, il codice continua. Qualche tempo dopo (non sai esattamente quando) verrà eseguita la tua azione asincrona
  • Invoke() eseguirà l'azione asincrona (sul thread della GUI) e attenderà il completamento dell'azione.

Una conclusione logica è che un delegato a cui si passa Invoke()può avere parametri out o un valore di ritorno, mentre un delegato a cui si passa BeginInvoke()non può (è necessario utilizzare EndInvoke per recuperare i risultati).


20

Giusto per fare un breve esempio di lavoro per vedere un effetto della loro differenza

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");
}

Se usi BeginInvoke , MessageBox si apre simultaneamente all'aggiornamento del testo. Se usi Invoke , MessageBox si apre dopo 3 secondi di sospensione. Quindi, mostrando l'effetto di una chiamata asincrona ( BeginInvoke ) e sincrona ( Invoke ).


9

Delegate.BeginInvoke () mette in coda in modo asincrono la chiamata di un delegato e restituisce immediatamente il controllo. Quando si utilizza Delegate.BeginInvoke (), è necessario chiamare Delegate.EndInvoke () nel metodo di callback per ottenere i risultati.

Delegate.Invoke () chiama in modo sincrono il delegato nello stesso thread.

Articolo MSDN


8

Aggiungo solo perché e quando usare Invoke ().

Sia Invoke () che BeginInvoke () eseguono il marshalling del codice specificato nel thread del dispatcher.

Ma a differenza di BeginInvoke (), Invoke () blocca il thread fino a quando il dispatcher non esegue il codice. È possibile che si desideri utilizzare Invoke () se è necessario sospendere un'operazione asincrona fino a quando l'utente non ha fornito una sorta di feedback.

Ad esempio, è possibile chiamare Invoke () per eseguire uno snippet di codice che mostri una finestra di dialogo OK / Annulla. Dopo che l'utente ha fatto clic su un pulsante e ha completato il codice su cui è stato eseguito il marshalling, verrà restituito il metodo invoke () e sarà possibile agire sulla risposta dell'utente.

Vedi Pro WPF nel capitolo 31 di C #

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.