Frage

Ich habe in WCF gesehen, dass sie das haben [OperationContract(IsOneWay = true)] Attribut. Aber WCF scheint langsam und schwer zu sein, nur um eine nicht blockierende Funktion zu erzeugen. Idealerweise würde es so etwas wie statische Leere ohne Blockierung geben MethodFoo(){}, aber ich glaube nicht, dass das existiert.

Was ist der schnellste Weg, um eine nicht blockierende Methode 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 beendet werden soll. (Siehe #2 Top -Antwort) Wenn die Methode fertig ist, müssen Sie an einigen Stellen wie einer ASP.NET -Anwendung etwas tun, um den Thread zu blockieren und am Leben zu erhalten. Andernfalls könnte dies zu "Fire-Forget-,-aber-Nor-takuell-Execute" 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)

War es hilfreich?

Lösung

ThreadPool.QueueUserWorkItem(o => FireAway());

(fünf Jahre später...)

Task.Run(() => FireAway());

Wie hervorgehoben von Luisperezphd.

Andere Tipps

Für C# 4.0 und neuer ist es mir, dass die beste Antwort jetzt von Ade Miller hier gegeben wird: Der einfachste Weg, ein Feuer zu machen und die Methode in C# 4.0 zu vergessen

Task.Factory.StartNew(() => FireAway());

Oder auch...

Task.Factory.StartNew(FireAway);

Oder...

new Task(FireAway).Start();

Wo FireAway ist

public static void FireAway()
{
    // Blah...
}

Daher schlägt die Threadpool -Version die Threadpool -Version um sechs und neunzehn Zeichen, je nachdem, was Sie wählen :)

ThreadPool.QueueUserWorkItem(o => FireAway());

Hinzufügen zu Wills Antwort, Wenn dies eine Konsolenanwendung ist, werfen Sie einfach eine ein AutoResetEvent und ein WaitHandle Um zu verhindern, dass es vor dem Abschluss des Arbeiter -Threads ausgeht:

Using System;
Using System.Threading;

class Foo
{
    static AutoResetEvent autoEvent = new AutoResetEvent(false);

    static void Main()
    {
        ThreadPoolQueueUserWorkItem(new WaitCallback(FireAway), autoEvent);
        autoEvent.WaitOne(); // Will wait for thread to complete
    }

    static void FireAway(object stateInfo)
    {
        System.Threading.Thread.Sleep(5000);
        Console.WriteLine("5 seconds later");
        ((AutoResetEvent)stateInfo).Set();
    }
}

Für .net 4.5:

Task.Run(() => FireAway());

Ein einfacher Weg ist, einen Thread mit parameterloser Lambda zu erstellen und zu starten:

(new Thread(() => { 
    FireAway(); 
    MessageBox.Show("FireAway Finished!"); 
}) { 
    Name = "Long Running Work Thread (FireAway Call)",
    Priority = ThreadPriority.BelowNormal 
}).Start();

Durch die Verwendung dieser Methode über Threadpool.queueuserworkItem können Sie Ihren neuen Thread benennen, um das Debuggen zu erleichtern. Vergessen Sie auch nicht, umfangreiche Fehlerbehandlungen in Ihrer Routine zu verwenden, da alle unberührten Ausnahmen außerhalb eines Debuggers Ihre Anwendung abrupt abbrechen:

enter image description here

Die empfohlene Methode, dies zu tun, wenn Sie ASP.NET und .NET 4.5.2 verwenden, erfolgt durch Verwendung QueueBackgroundWorkItem. Hier ist eine Helferklasse:

public static class BackgroundTaskRunner
{     
    public static void FireAndForgetTask(Action action)
    {
        HostingEnvironment.QueueBackgroundWorkItem(cancellationToken => // .Net 4.5.2 required
        {
            try
            {
                action();
            }
            catch (Exception e)
            {
                // TODO: handle exception
            }
        });
    }

    /// <summary>
    /// Using async
    /// </summary>
    public static void FireAndForgetTask(Func<Task> action)
    {
        HostingEnvironment.QueueBackgroundWorkItem(async cancellationToken => // .Net 4.5.2 required
        {
            try
            {
                await action();
            }
            catch (Exception e)
            {
                // TODO: handle exception
            }
        });
    }
}

Verwendungsbeispiel:

BackgroundTaskRunner.FireAndForgetTask(() =>
{
    FireAway();
});

oder mit Asynchronisation:

BackgroundTaskRunner.FireAndForgetTask(async () =>
{
    await FireAway();
});

Dies funktioniert hervorragend auf Azure -Websites.

Bezug: Verwenden von QueubackgroundworkItem, um Hintergrundjobs von einer ASP.NET -Anwendung in .NET 4.5.2 zu planen

Anrufen von Beginninvoke und nicht zu Endeinvoke ist kein guter Ansatz. Antwort ist einfach: Der Grund, warum Sie Endinvoke aufrufen sollten, ist, dass die Ergebnisse des Aufrufs (auch wenn es keinen Rückgabewert gibt) von .NET zwischen .NET zwischengespeichert werden dürfen, bis Endinvoke aufgerufen wird. Wenn der aufgerufene Code beispielsweise eine Ausnahme ausgelöst hat, wird die Ausnahme in den Aufrufdaten zwischengespeichert. Bis Sie Endinvoke anrufen, bleibt es im Speicher. Nachdem Sie Endinvoke angerufen haben, kann der Speicher veröffentlicht werden. Für diesen speziellen Fall ist es möglich, dass der Speicher bleibt, bis der Prozess abgeschaltet wird, da die Daten intern durch den Aufrufcode geführt werden. Ich denke, der GC könnte es irgendwann sammeln, aber ich weiß nicht, wie der GC wissen würde, dass Sie die Daten aufgegeben haben, im Vergleich zu einer sehr langen Zeit, um sie abzurufen. Ich bezweifle, dass es tut. Daher kann ein Speicherleck auftreten.

Weitere können auf gefunden werden http://haacked.com/archive/2009/01/09/asynchronous-fire-forget-with-lambdas.aspx

Der einfachste .NET 2.0- und spätere Ansatz ist das asynchnonische Programmiermodell (dh aninvoke auf einem Delegierten):

static void Main(string[] args)
{
      new MethodInvoker(FireAway).BeginInvoke(null, null);

      Console.WriteLine("Main: " + Thread.CurrentThread.ManagedThreadId);

      Thread.Sleep(5000);
}

private static void FireAway()
{
    Thread.Sleep(2000);

    Console.WriteLine("FireAway: " + Thread.CurrentThread.ManagedThreadId );  
}

Almost 10 years later:

Task.Run(FireAway);

I would add exception handling and logging inside FireAway

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top