Invoke e BeginInvoke

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 alcuni thread e ho trovato alcune informazioni utili qui: qui

Tuttavia, qual è la differenza tra Invoke e BeginInvoke nel seguente codice:

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 quando 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.

    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 devi chiamare EndInvoke per ottenere i risultati del metodo che hai eseguito usando BeginIvnoke.

    Non è necessario 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 è ansible accedere ai componenti dell’interfaccia utente in un thread diverso per il thread della GUI.

    Spero che questo ti aiuti!

    Per iniziare, dal tuo link:

    • Control.Invoke : esegue sul thread dell’interfaccia utente, ma la chiamata del thread attende il completamento prima di continuare.
    • Control.BeginInvoke : esegue il thread dell’interfaccia utente asincrona e il thread chiamante non attende il completamento.

    e da MSDN:

    BeginInvoke esegue il delegato specificato in modo asincrono sul thread su cui è stato creato l’handle sottostante del controllo.

    Per riassumere, BeginInvoke è asincrono . Quando BeginInvoke viene chiamato 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.

    Control.BeginInvoke non funziona su un thread diverso (o threadpool), un delegate.BeginInvoke lo fa. Il rivestimento di MSDN dice:

    Esegue il delegato specificato in modo asincrono sul thread su cui è stato creato l’handle sottostante del controllo.

    Tuttavia Control.BeginInvoke utilizza semplicemente PostMessage e restituisce – non viene creato alcun Thread CLR.

    La funzione PostMessage inserisce (post) un messaggio nella coda messaggi associata al thread che ha creato la finestra specificata e restituisce senza attendere che il thread elabori il messaggio.

    In questo articolo viene riepilogato se utilizzare Invoke o BeginInvoke abbastanza bene:

    Quale funzione usare, chiedi. Dipende davvero dalle tue esigenze. Se si desidera completare l’aggiornamento dell’interfaccia utente prima di procedere, si utilizza Invoke. Se non esiste un tale requisito, suggerirei di utilizzare BeginInvoke, in quanto rende il thread chiamandolo apparentemente “più veloce”. Tuttavia, ci sono alcuni problemi con BeginInvoke.

    • Se la funzione che stai chiamando tramite BeginInvoke accede a uno stato condiviso (stato condiviso tra il thread dell’interfaccia utente e altri thread), sei nei guai. Lo stato potrebbe cambiare tra il momento in cui hai chiamato BeginInvoke e quando la funzione wrapping viene effettivamente eseguita, portando a problemi di temporizzazione difficili da trovare.
    • Se si passano i parametri di riferimento alla funzione chiamata tramite BeginInvoke, è necessario assicurarsi che nessun altro modifichi l’object passato prima che la funzione venga completata. Di solito, le persone clonano l’object prima di passarlo a BeginInvoke, che evita del tutto il problema.

    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.

    Questo in sostanza si riduce a se si desidera o meno che il controllo sia aggiornato in modo sincrono o asincrono. Tutto dipende dalla tua situazione specifica.