2008-10-23 7 views
14

Ich versuche, etwas asynchrone Sachen in einer Webservice-Methode zu tun. Nehmen wir an, ich habe den folgenden API-Aufruf: http://www.example.com/api.asmx.NET Web Service & BackgroundWorker Themen

und die Methode heißt GetProducts().

Ich diese GetProducts-Methoden, ich mache ein paar Sachen (zB Daten aus der Datenbank) dann kurz bevor ich das Ergebnis zurückgebe, möchte ich etwas asynchrone Sachen (zB senden Sie mir eine E-Mail).

Also das ist was ich getan habe.

[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(); 
    } 
} 

Jetzt, wenn ich diesen Code ausführen, wird die E-Mail nie gesendet. Wenn ich den Thread.Sleep auslasse, wird die E-Mail gesendet.

Also ... warum ist der Hintergrund Worker Thread abgerissen? hängt es vom übergeordneten Thread ab? Ist das der falsche Weg, den ich tun sollte, Hintergrund oder gespalten Threading, in asp.net Web-Anwendungen?

Antwort

17

BackgroundWorker ist nützlich, wenn Sie z. B. aus Affinitätsgründen (z. B.) mit einem UI * -Thread synchronisieren müssen. In diesem Fall scheint es, dass die einfache Verwendung von ThreadPool mehr als ausreichend wäre (und viel einfacher). Wenn Sie hohe Volumina aufweisen, dann kann ein Erzeuger/Verbraucher-Warteschlange besser Drosselung erlauben (so dass Sie nicht ertrinken in Threads) - aber ich vermute, ThreadPool hier wird gut ...

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

auch - ich bin nicht ganz sicher, was du durch schlafen erreichen willst? Dies bindet nur einen Thread (ohne CPU, aber auch nicht gut). Pflege um zu erarbeiten? Es sieht wie Sie Ihre aktuelle Webseite pausieren (d. H. Der Schlaf passiert auf dem Web-Seite-Thread, nicht der E-Mail-Thread). Was versuchst du hier zu machen?

* = tatsächlich, wird es verwenden, was Sync-Kontext vorhanden ist

+0

Der Schlaf ist auskommentiert. Ich habe das da hingestellt, um zu sehen, ob ich eine E-Mail schicken könnte. Wenn der Schlaf nicht KOMMENTIERT ist, wird der Hintergrund-Worker-Thread-Code ausgeführt. Wenn der Code ausgegeben wird, wird der Hintergrund-Worker-Thread-Code niemals ausgeführt. Ich werde stattdessen ThreadPool verwenden. –

+0

> * Wenn Sie hohe Volumina haben, kann eine Producer/Consumer Queue eine bessere Throttling erlauben (damit Sie nicht in Threads ertrinken) * ooooooo !!!Ich bin froh, dass du diesen Punkt angesprochen hast! Die Web-Service-Methode ist eigentlich ein hohes Volumen! Außerdem, um die Sache wirklich interessant zu machen, sendet es nicht wirklich eine E-Mail, sondern trifft eine andere externe Website (ekk, frag nicht) ... also würdest du vorschlagen, dass ich dieses Producer/Consumer-Queue-Thingy mache? Wenn ja ... ist das eine gute Referenz? http://www.albahari.com/threading/part4.aspx (scrollen Sie bitte ein wenig nach unten zum Code + ein Beispiel). Gedanken? –

+0

@Marc Gravell Ich habe versucht, Ihre Lösung zu verwenden, aber ich frage mich nur, warum es zu viel Zeit braucht, um die Aufgabe abzuschließen. – AnandMohanAwasthi

0

Es zerrissen, weil nach 20 Sekunden ab, dass Background Beispiel Müll gesammelt werden können, weil sie keine Referenzen hat (out of scope gegangen).

+0

Beachten Sie, dass der Sleep() auf dem Thread der Webseite ist; Es ist wahrscheinlicher, dass der BackgroundWorker versucht, einen Sync-Kontext zu verwenden, der von Sleep() selbst blockiert wird –

1

Re Produzent/Verbraucher; im Grunde - es ist einfach wert, einige Art von Drossel zu halten. Auf der einfachsten Ebene könnte ein Semaphore (zusammen mit dem regulären ThreadPool) verwendet werden, um Dinge auf eine bekannte Menge an Arbeit zu beschränken (um die Sättigung des Thread-Pools zu vermeiden); aber eine Erzeuger/Verbraucher-Schlange wäre wahrscheinlich effizienter und würde verwaltet werden.

Jon Skeet hat eine solche Warteschlange here (CustomThreadPool). Ich könnte wahrscheinlich ein paar Notizen darüber schreiben, wenn Sie wollten.

Das sagte: Wenn Sie auf eine externe Website aufrufen, ist es sehr wahrscheinlich, dass Sie eine Menge Wartezeiten auf Netzwerk IO/Completion-Ports haben werden; Als solche können Sie eine etwas höhere Anzahl von Threads haben ... (im Gegensatz dazu), wenn die Arbeit CPU-gebunden war, hat es keinen Sinn, mehr Threads zu haben als CPU-Kerne.