Ich habe in WCF gesehen, dass sie das [OperationContract(IsOneWay = true)]
Attribut haben. Aber WCF scheint langsam und schwer zu sein, nur um eine nicht blockierende Funktion zu erstellen. Idealerweise würde es so etwas wie statische Leere geben MethodFoo(){}
, die nicht blockiert , aber ich glaube nicht, dass es das gibt.
Was ist der schnellste Weg, um einen nicht blockierenden Methodenaufruf in C # zu erstellen?
Z.B
class Foo
{
static void Main()
{
FireAway(); //No callback, just go away
Console.WriteLine("Happens immediately");
}
static void FireAway()
{
System.Threading.Thread.Sleep(5000);
Console.WriteLine("5 seconds later");
}
}
NB : Jeder, der dies liest, sollte darüber nachdenken, ob die Methode tatsächlich abgeschlossen werden soll. (Siehe Antwort Nr. 2 oben) Wenn die Methode beendet werden muss, müssen Sie an einigen Stellen, z. B. in einer ASP.NET-Anwendung, etwas tun, um den Thread zu blockieren und am Leben zu erhalten. Andernfalls könnte dies zu "Feuer-Vergessen-aber-nie-tatsächlich-Ausführen" führen. In diesem Fall wäre es natürlich einfacher, überhaupt keinen Code zu schreiben. ( Eine gute Beschreibung, wie dies in ASP.NET funktioniert )
quelle
(new Action(FireAway)).BeginInvoke()
Task.Factory.StartNew(() => myevent());
von Antwort stackoverflow.com/questions/14858261/…Für C # 4.0 und neuere Versionen fällt mir auf, dass Ade Miller hier jetzt die beste Antwort gibt: Einfachste Methode, um eine Feuer- und Vergessensmethode in C # 4.0 auszuführen
quelle
FireAway
?Task.Factory.StartNew(() => FireAway(foo));
.Task.Factory.StartNew(() => FireAway(foo));
Für .NET 4.5:
quelle
Task.Factory.StartNew(() => FireAway(), CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
laut blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspxUm Wills Antwort zu ergänzen , wenn dies eine Konsolenanwendung ist, geben Sie einfach ein
AutoResetEvent
und ein einWaitHandle
, um zu verhindern, dass sie beendet wird, bevor der Arbeitsthread abgeschlossen ist:quelle
WaitOne
blockiert immer undAutoResetEvent
wird immer funktionierenWaitHandle
s haben, jedes mit einem eigenenAutoResetEvent
und einem entsprechendenThreadPool.QueueUserWorkItem
. Danach einfachWaitHandle.WaitAll(arrayOfWaitHandles)
.Eine einfache Möglichkeit besteht darin, einen Thread mit parameterlosem Lambda zu erstellen und zu starten:
Mit dieser Methode über ThreadPool.QueueUserWorkItem können Sie Ihren neuen Thread benennen, um das Debuggen zu vereinfachen. Vergessen Sie auch nicht, in Ihrer Routine eine umfassende Fehlerbehandlung zu verwenden, da nicht behandelte Ausnahmen außerhalb eines Debuggers Ihre Anwendung abrupt zum Absturz bringen:
quelle
Die empfohlene Vorgehensweise bei Verwendung von Asp.Net und .Net 4.5.2 ist die Verwendung von
QueueBackgroundWorkItem
. Hier ist eine Hilfsklasse:Anwendungsbeispiel:
oder mit async:
Dies funktioniert hervorragend auf Azure-Websites.
Referenz: Verwenden von QueueBackgroundWorkItem zum Planen von Hintergrundjobs aus einer ASP.NET-Anwendung in .NET 4.5.2
quelle
Es ist kein guter Ansatz, beginInvoke aufzurufen und EndInvoke nicht abzufangen. Die Antwort ist einfach: Der Grund, warum Sie EndInvoke aufrufen sollten, besteht darin, dass die Ergebnisse des Aufrufs (auch wenn kein Rückgabewert vorhanden ist) von .NET zwischengespeichert werden müssen, bis EndInvoke aufgerufen wird. Wenn der aufgerufene Code beispielsweise eine Ausnahme auslöst, wird die Ausnahme in den Aufrufdaten zwischengespeichert. Bis Sie EndInvoke aufrufen, bleibt es im Speicher. Nachdem Sie EndInvoke aufgerufen haben, kann der Speicher freigegeben werden. In diesem speziellen Fall ist es möglich, dass der Speicher bis zum Herunterfahren des Prozesses erhalten bleibt, da die Daten intern durch den Aufrufcode verwaltet werden. Ich denke, der GC könnte es irgendwann sammeln, aber ich weiß nicht, woher der GC wissen würde, dass Sie die Daten aufgegeben haben, anstatt nur sehr lange zu brauchen, um sie abzurufen. Ich bezweifle es. Daher kann ein Speicherverlust auftreten.
Weitere Informationen finden Sie unter http://haacked.com/archive/2009/01/09/asynchronous-fire-and-forget-with-lambdas.aspx
quelle
BeginInvoke
ein Wrapper-Objekt zurückgegeben wird, das einen Verweis auf das Objekt enthält, auf das die tatsächlichen Ergebnisdaten enthalten, auf das jedoch nicht verwiesen wird, kann das Wrapper-Objekt finalisiert werden, sobald alle Verweise darauf aufgegeben wurden.Fast 10 Jahre später:
Ich würde die Ausnahmebehandlung und Protokollierung in FireAway hinzufügen
quelle
Der einfachste Ansatz für .NET 2.0 und höher ist die Verwendung des asynchronen Programmiermodells (dh BeginInvoke für einen Delegaten):
quelle
Task.Run()
existierte, war dies wahrscheinlich der prägnanteste Weg, dies zu tun.