Domanda

Sto provando a fare alcune cose asincrone in un metodo di servizio web. Supponiamo che io abbia la seguente chiamata API: http://www.example.com/api.asmx

e il metodo si chiama GetProducts () .

Con questi metodi GetProducts, faccio alcune cose (ad es. ottenere dati dal database), quindi appena prima di restituire il risultato, voglio fare alcune cose asincrone (ad es. mandami una email).

Quindi questo è quello che ho fatto.

[WebMethod(Description = "Bal blah blah.")]
public IList<Product> GetProducts()
{
    // Blah blah blah ..
    // Get data from DB .. hi DB!
    // var myData = .......
    // Moar clbuttic blahs :)  (yes, google for clbuttic if you don't know what that is)

    // Ok .. now send me an email for no particular reason, but to prove that async stuff works.
    var myObject = new MyObject();
    myObject.SendDataAsync();

    // Ok, now return the result.
    return myData;
    }
}

public class TrackingCode
{
    public void SendDataAsync()
    {
        var backgroundWorker = new BackgroundWorker();
        backgroundWorker.DoWork += BackgroundWorker_DoWork;
        backgroundWorker.RunWorkerAsync();
        //System.Threading.Thread.Sleep(1000 * 20);
    }

    private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        SendEmail();
    }
}

Ora, quando eseguo questo codice, l'e-mail non viene mai inviata. Se decomprimo il Thread.Sleep .. allora l'e-mail viene inviata.

Quindi ... perché il thread di lavoro in background è stato demolito? dipende dal thread principale? È questo il modo sbagliato in cui dovrei fare il threading in background o in fork, nelle app web asp.net?

È stato utile?

Soluzione

BackgroundWorker è utile quando è necessario sincronizzare nuovamente (ad esempio) un thread UI *, ad esempio per motivi di affinità. In questo caso, sembrerebbe che usare semplicemente ThreadPool sarebbe più che adeguato (e molto più semplice). Se hai volumi elevati, una coda produttore / consumatore può consentire una migliore limitazione (quindi non annegare nei thread) - ma sospetto che ThreadPool andrà bene qui ...

public void SendDataAsync()
{
    ThreadPool.QueueUserWorkItem(delegate
    {
        SendEmail();
    });
}

Inoltre - Non sono sicuro di cosa tu voglia ottenere dormendo? Questo collegherà semplicemente un thread (non usando la CPU, ma non facendo nulla di buono). Ti interessa elaborare? sembra come se stessi mettendo in pausa la tua pagina Web effettiva (ovvero la sospensione avviene sul thread della pagina Web, non sul thread di posta elettronica). Cosa stai cercando di fare qui?

* = in realtà, utilizzerà qualsiasi contesto di sincronizzazione in atto

Altri suggerimenti

Re produttore / consumatore; in sostanza - vale la pena mantenere un po 'di acceleratore. Al livello più semplice, è possibile utilizzare un Semaphore (insieme al normale ThreadPool ) per limitare le cose a una quantità nota di lavoro (per evitare di saturare il pool di thread); ma una coda produttore / consumatore sarebbe probabilmente più efficiente e gestita.

Jon Skeet ha una tale coda qui ( CustomThreadPool ). Probabilmente potrei scrivere alcune note a riguardo se lo desideri.

Detto questo: se si sta effettuando una chiamata a un sito Web esterno, è molto probabile che si verifichino molte attese sulle porte IO / di completamento della rete; come tale, puoi avere un numero leggermente più alto di thread ... ovviamente (al contrario) se il lavoro era associato alla CPU, non ha senso avere più thread di quanti ne hai i core della CPU.

Potrebbe essere abbattuto perché dopo 20 secondi quell'istanza di BackgroundWorker potrebbe essere raccolta in modo errato perché non ha riferimenti (non rientra nell'ambito).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top