2009-12-15 13 views
16

Saluti, Sto sviluppando alcune applicazioni in C#. Al momento ho a che fare con il threading e ho una domanda che ho in mente. Qual è la differenza tra Invoke e BeginInvoke? Ho letto alcune filo e ho trovato qui alcune informazioni utili: hereInvoke e BeginInvoke

Tuttavia ciò che è la differenza tra Invoke e BeginInvoke nel codice seguente:

private void ProcessRoutine() 
{ 
    for (int nValue = StartFrom; nValue <= EndTo; nValue++) 
    { 
     this.Invoke(this.MyDelegate, nValue); 
     //this.BeginInvoke(this.MyDelegate, nValue); 
    } 
    MessageBox.Show("Counting complete!"); 
} 
private void MessageHandler(int progress) 
{ 
    lblStatus.Text = lblStatus.Text = "Processing item: " + progress.ToString(); 
    progressBar1.Value = progress; 
} 

dove MyDelegate è un riferimento alla funzione messageHandler.

Ho notato che l'utilizzo di BeginInvoke lblStatus.Text non è stato aggiornato dove l'utilizzo di Invoke aggiorna l'etichetta. Inoltre so che Invoke attende il completamento dell'esecuzione. Il caso più importante a cui sono interessato è il motivo per cui in questo caso c'è una differenza nell'aggiornamento del testo dell'etichetta.

risposta

8

Con Invoke il metodo viene eseguito e l'applicazione attende il suo completamento.

Con BeginInvoke il metodo viene richiamato in modo asincrono e l'applicazione continua a essere eseguita mentre viene eseguito il metodo referenziato in BeginInvoke.

Con BeginInvoke è necessario chiamare EndInvoke per ottenere i risultati del metodo eseguito utilizzando BeginIvnoke.

Non aggiornare i componenti della GUI nei metodi BeginXXX poiché vengono eseguiti in un altro thread per il thread della GUI, contrariamente al metodo Invoke. Non è possibile accedere ai componenti dell'interfaccia utente in un thread diverso per il thread della GUI.

Spero che questo aiuti!

+12

Calling BeginInvoke non significa che non è eseguito l'interfaccia utente filo. Significa che è chiamato in modo asincrono sul thread associato a "this" che potrebbe essere il thread dell'interfaccia utente. –

+0

quindi, se non è in un altro thread, come funziona allora? –

+8

Da MSDN: "Esegue il delegato specificato in modo asincrono sul thread su cui è stato creato l'handle sottostante del controllo". Quindi, se viene chiamato dal thread dell'interfaccia utente, verrà inserito in una coda ed eseguito quando l'interfaccia utente lo inattiva. Quale sarà dopo il ritorno del metodo attualmente in esecuzione. –

1

BeginInvoke esegue il corpo del metodo su un altro thread e consente al thread corrente di continuare. Se si sta tentando di aggiornare direttamente una proprietà di controllo da un altro thread, verrà generata un'eccezione.

+1

sì, lo so, ma il motivo per cui utilizzando Richiamare il mio testo dell'etichetta viene aggiornata ed usando BeginInvoke non lo è –

+0

@Niao vedere la seconda frase della mia risposta –

0

Questo in pratica si riduce alla necessità o meno di aggiornare il controllo in modo sincrono o asincrono. Tutto dipende dalla tua situazione specifica.

18

Per iniziare, dal tuo link:

  • Control.Invoke: Esegue sul thread UI, ma chiamando thread attende il completamento prima di continuare.
  • Control.BeginInvoke: esegue il thread dell'interfaccia utente asincrona e il thread di chiamata non attende il completamento.

e da MSDN:

BeginInvoke esegue il delegato specificato asincrono sul filo che handle sottostante del controllo è stato creato il.

Riassumendo, BeginInvoke è asincrono. Quando si chiama BeginInvoke dal thread dell'interfaccia utente, la richiesta verrà eseguita in parallelo con il thread dell'interfaccia utente. Il che significa che non può essere eseguito fino a quando non viene restituito il metodo attualmente in esecuzione.In questo caso, la casella di testo non verrà mai aggiornata perché il ciclo for non verrà interrotto, poiché il thread chiamante non aspetterà che questo evento venga completato prima di continuare.

In alternativa, Invoke è sincrono. La casella di testo verrà aggiornata perché il thread chiamante attenderà il completamento della chiamata prima di continuare l'esecuzione.

+2

Un punto minore: non viene eseguito quando il metodo ritorna, è fatto come un incendio e dimentica: viene sparato nel COM/Winapi ether –

+0

Grazie per il tuo feedback; Ho appena aggiornato la mia risposta. –

5

Control.BeginInvoke non funziona su un thread diverso (o threadpool), un delegate.BeginInvoke. uno di linea di MSDN dice:

Esegue il delegato specificato asincrono sul filo che handle sottostante del controllo era creato su.

Tuttavia Control.BeginInvoke usa semplicemente PostMessage ritorni - non CLR è creato Thread.

La funzione PostMessage pone (messaggi) di un messaggio nella coda dei messaggi associato al thread che creato la finestra specificata e restituisce senza attendere il filo per elaborare il messaggio.

This article riassume se utilizzare o InvokeBeginInvoke abbastanza bene:

che funzionano da usare, si chiede. È in realtà dipende dalle vostre esigenze. Se vuoi che il tuo aggiornamento dell'interfaccia utente completi prima di procedere, usi Invoke. Se non esiste un tale requisito, io suggerisco di utilizzare BeginInvoke, in quanto rende il thread che lo chiama apparentemente "più veloce". Tuttavia, con BeginInvoke sono disponibili alcuni getcha .

  • Se la funzione che si sta chiamando tramite BeginInvoke accessi condivisi stato (stato condiviso tra il thread UI e altri thread), ci si trova in guai. Lo stato potrebbe cambiare tra il momento in cui hai chiamato BeginInvoke e quando la funzione completata viene effettivamente eseguita, causando problemi di temporizzazione di difficili da trovare.
  • Se si passano i parametri di riferimento alla funzione denominata tramite BeginInvoke, è necessario assicurarsi che nessun altro modifichi l'oggetto passato prima che la funzione venga completata. Di solito, le persone clonano l'oggetto prima di passarlo a BeginInvoke, che evita del tutto il problema.
Problemi correlati