2010-03-18 10 views
6

Ho ereditato il codice in cui BeginInvoke viene chiamato dal thread principale (non un thread in background, che di solito è il pattern). Sto cercando di capire cosa fa effettivamente in questo scenario.Implicazioni sulle prestazioni di BeginInvoke

Il metodo richiamato in BeginInvoke si allinea ai messaggi che arrivano fino alla finestra? I documenti dicono asynchronously, quindi questa è la mia ipotesi.

Come fa la priorità del framework quando avviare il metodo chiamato BeginInvoke?

Edit: Il codice è simile al seguente:

System.Action<bool> finalizeUI = delegate(bool open) 
{ 
    try 
    { 
     // do somewhat time consuming stuff 
    } 
    finally 
    { 
     Cursor.Current = Cursors.Default; 
    } 
}; 

Cursor.Current = Cursors.WaitCursor; 
BeginInvoke(finalizeUI, true); 

Questo sta accadendo nel Form_Load.

risposta

4

modificare

Ora che vediamo il codice, è chiaro che questo è solo un modo per spostare alcuni di inizializzazione di Form_Load ma hanno ancora accadere prima che l'utente può interagire con il modulo.

La chiamata a BeginInvoke si trova in Form_load e non viene richiamata su un altro oggetto, quindi questa è una chiamata a Form.BeginInvoke. Quindi quello che sta succedendo è questo.

  1. Form_Load passa un delegato alla Form.BeginInvoke, questo mette un messaggio nella coda di messaggi del modulo che è avanti di tutti i messaggi di input utente. Imposta il cursore su un cursore di attesa.
  2. Restituisce Form_Load e il completamento dell'inizializzazione del modulo è consentito, il modulo molto probabilmente diventa visibile a questo punto.
  3. Una volta che il codice cade nel messaggio pompa, la prima cosa che vede in coda è il delegato, quindi esegue quello.
  4. al completamento del delegato, riporta il cursore al cursore normale e restituisce
  5. profitto!

originale post qui sotto


Ho dipende dall'oggetto che si chiama BeginInvoke su. Se l'oggetto è derivato da Control allora Control.BeginInvoke verrà eseguito sul thread che ha creato il controllo. Vedi la risposta di JaredPar.

Ma esiste un altro schema per l'utilizzo di BeginInvoke. se l'oggetto è un delegato, BeginInvoke esegue il callback su un thread separato, uno che può essere creato appositamente per tale scopo.

public class Foo 
{ 
    ... 
    public Object Bar(object arg) 
    { 
     // this function will run on a separate thread. 
    } 
} 

... 

// this delegate is used to Invoke Bar on Foo in separate thread, this must 
// take the same arguments and return the same value as the Bar method of Foo 
public delegate object FooBarCaller (object arg); 

... 

// call this on the main thread to invoke Foo.Bar on a background thread 
// 
public IAsyncResult BeginFooBar(AsyncCallback callback, object arg) 
{ 
    Foo foo = new Foo(); 
    FooBarCaller caller = new FooBarCaller (foo.Bar); 
    return caller.BeginInvoke (arg); 
} 

Questo motivo è uno dei motivi per cui BeginInvoke viene chiamato dal thread principale anziché da un thread in background.

+0

@John Knoeller, stai dicendo che nel mio scenario, BeginInvoke ha il peso dell'interruttore di contesto del thread? – AngryHacker

+0

@AngryHacker: No, ora che hai mostrato il tuo codice, è chiaro che questo è solo un PostMessage come descritto da JaredPar, il tuo BeginInvoke è un metodo sul modulo, e quindi _non_ esegui il delegato su un thread separato. –

2

Nel caso in cui BeginInvoke venga chiamato su un thread dell'interfaccia utente, continuerà comunque a inviare un messaggio di Windows alla coda messaggi in cui il messaggio attende di essere elaborato. Il delegato verrà eseguito quando il messaggio viene elaborato. Questo messaggio non ha la priorità in alcun modo diverso da come viene chiamato dal thread in background.

+1

Non aspetta. –

+0

@nobugz, terribile formulazione da parte mia. Stavo cercando di dire che il messaggio stesso siederà in coda dove attende di essere elaborato, non che il chiamante sia in attesa. Pulito la lingua. – JaredPar

+0

Sei sicuro di questo? BeginInvoke è PostMessage anziché SendMessage o SendNotifyMessage? –

1

In questo scenario ho il sospetto la chiamata appare come:

private void Button1_Click(object sender, ButtonClickEventArgs e) 
{ 
    Control.BeginInvoke(new MethodInvoker(()=> /* code etc. */)); 
} 

Quello che sta succedendo è che un codice verrà eseguito su su un thread ThreadPool, e aggiornare il controllo sul thread che ha creato il controllo mentre se È stato utilizzato Control.Invoke, , il codice si eseguirebbe sul thread che ha creato il controllo e aggiornerà anche il controllo su quel thread.

1

Prima dell'uso diffuso di BackgroundWorker, era necessario eseguire la sincronizzazione sul thread dell'interfaccia utente prima di eseguire qualsiasi operazione sui controlli creati nel thread dell'interfaccia utente (ovvero quasi ogni controllo).

C'è un buon esempio di riferimento here in basso nella sezione "Thread-Safe to a Windows Form Control".