188

I saw in WCF they have the [OperationContract(IsOneWay = true)] attribute. But WCF seems kind of slow and heavy just to do create a nonblocking function. Ideally there would be something like static void nonblocking MethodFoo(){}, but I don't think that exists.

What is the quickest way to create a nonblocking method call in C#?

E.g.

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: Everyone reading this should think about if they actually want the method to finish. (See #2 top answer) If the method has to finish, then in some places, like an ASP.NET application, you will need to do something to block and keep the thread alive. Otherwise, this could lead to "fire-forget-but-never-actually-execute", in which case,of course, it would be simpler to write no code at all. (A good description of how this works in ASP.NET)

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
MatthewMartin
  • 32,326
  • 33
  • 105
  • 164

11 Answers11

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

(five years later...)

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

as pointed out by luisperezphd.

  • You win. No, really, this seems to be the shortest version, unless you encapsulate that into another function. – OregonGhost Jun 19 '09 at 15:40
  • 15
    Thinking about this... in most applications this is fine, but in yours the console app will exit before FireAway sends anything to the console. ThreadPool threads are background threads and die when the app dies. On the other hand, using a Thread wouldn't work either as the console window would disappear before FireAway tried to write to the window. –  Jun 19 '09 at 15:41
  • 3
    There is no way to have a non-blocking method call that is guaranteed to run, so this is in fact the most accurate answer to the question IMO. If you need to guarantee execution then potential blocking needs to be introduced via a control structure such as AutoResetEvent (as Kev mentioned) – Guvante Jun 19 '09 at 17:40
  • +1 This syntax is hard to find searching for parameterless lambdas – Maslow Jul 03 '09 at 13:25
  • 2
    To run the task in a thread independent of the thread pool, I believe you could also go `(new Action(FireAway)).BeginInvoke()` – Sam Harwell Sep 14 '09 at 19:01
  • @280Z28 the only problem with that approach is any Exceptions that occur will be gobbled until you call EndInvoke. Seeing as you haven't kept a reference to the Action you'll never be able to call EndInvoke. – Doctor Jones Sep 23 '10 at 14:57
  • @Will to see the output in console application, just put Console.ReadLine(); at the end of Main function :) – Andrija May 13 '13 at 05:58
  • 2
    What about this `Task.Factory.StartNew(() => myevent());` from answer http://stackoverflow.com/questions/14858261/fire-event-on-background-thread – Luis Perez Dec 28 '14 at 17:58
  • @luisperezphd Look at the date on this answer. Of course, `Task.Run` would be even shorter. I'll add that to my answer with a cred and link. Thanks. (edit) The link doesn't make sense in the context of your comment; I'm removing that from the question. –  Dec 29 '14 at 18:16
  • Isn't the even simpler like `_ = FireAway();` ? – krypru Aug 09 '21 at 16:05
43

For C# 4.0 and newer, it strikes me that the best answer is now given here by Ade Miller: Simplest way to do a fire and forget method in c# 4.0

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

Or even...

Task.Factory.StartNew(FireAway);

Or...

new Task(FireAway).Start();

Where FireAway is

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

So by virtue of class and method name terseness this beats the threadpool version by between six and nineteen characters depending on the one you choose :)

ThreadPool.QueueUserWorkItem(o => FireAway());
Community
  • 1
  • 1
Patrick Szalapski
  • 8,738
  • 11
  • 67
  • 129
  • 13
    I am most interested in having the best answers easily available on good questions. I would definitely encourage others to do the same. – Patrick Szalapski Dec 18 '14 at 19:21
  • 3
    According to http://stackoverflow.com/help/referencing, you are required to use blockquotes to indicate that you are quoting from another source. As it is your answer appears to be all your own work. Your intention by re-posting an exact copy of the answer could have been achieved with a link in a comment. – tom redfern Dec 19 '14 at 10:25
  • 1
    how to pass parameters to `FireAway`? – GuidoG Jun 22 '18 at 07:32
  • I believe you'd have to use the first solution: `Task.Factory.StartNew(() => FireAway(foo));`. – Patrick Szalapski Jun 22 '18 at 16:30
  • 1
    be cautious while using `Task.Factory.StartNew(() => FireAway(foo));` foo cannot be modified in loop as explained [here](https://blogs.msdn.microsoft.com/ericlippert/2009/11/12/closing-over-the-loop-variable-considered-harmful/) and [here](https://stackoverflow.com/questions/14297633/c-sharp-pass-lambda-expression-as-method-parameter) – AaA Jul 16 '18 at 07:12
  • `Task.Run` is the preferred way to let the framework handle execution, other methods could potentially cause deadlocks. The methods above have arguments that lets you control what TaskScheduler etc to be used. If you're not changing them, use defaults. – Jonas Stensved Apr 06 '20 at 07:52
30

For .NET 4.5:

Task.Run(() => FireAway());
nawfal
  • 70,104
  • 56
  • 326
  • 368
David Murdoch
  • 87,823
  • 39
  • 148
  • 191
  • 20
    Fyi, this is mainly short for `Task.Factory.StartNew(() => FireAway(), CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);` according to http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx – Jim Geurts Oct 31 '13 at 20:58
  • 1
    In the interest of posterity, the article linked to be @JimGeurts in their comment is now 404'd (thanks, MS!). Given the datestamp in that url, this article by Stephen Toub appears to be the correct one - https://devblogs.microsoft.com/pfxteam/task-run-vs-task-factory-startnew/ – Dan Atkinson May 22 '20 at 15:20
  • 1
    @DanAtkinson you are correct. Here is the original at archive.org, just in case MS moves it again: https://web.archive.org/web/20160226022029/http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx – David Murdoch May 29 '20 at 20:46
17

To add to Will's answer, if this is a console application, just throw in an AutoResetEvent and a WaitHandle to prevent it exiting before the worker thread completes:

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();
    }
}
Community
  • 1
  • 1
Kev
  • 118,037
  • 53
  • 300
  • 385
  • if this is not a console app and my C# class is COM Visible , will your AutoEvent works ? Is autoEvent.WaitOne() blocking ? – dan_l May 29 '12 at 09:36
  • 5
    @dan_l - No idea, why not ask that as a new question and make a reference to this one. – Kev May 29 '12 at 10:17
  • @dan_l, yes `WaitOne` is always blocking and [`AutoResetEvent`](https://msdn.microsoft.com/en-us/library/system.threading.autoresetevent.aspx) will always work – AaA Jul 16 '18 at 07:21
  • AutoResetEvent only really works here if there is a single background thread. I wonder if a Barrier would be better when multiple threads are in use. https://learn.microsoft.com/en-us/dotnet/standard/threading/barrier – Martin Brown Apr 03 '19 at 08:52
  • @MartinBrown - not sure that's true. You can have an array of `WaitHandle`s, each one with its own `AutoResetEvent` and a corresponding `ThreadPool.QueueUserWorkItem`. After that just `WaitHandle.WaitAll(arrayOfWaitHandles)`. – Kev Apr 03 '19 at 13:52
  • But if you use a Barrier, unless I'm mistaken, you would only need one for all the threads rather than maintaining a whole array of WaitHandles. – Martin Brown Apr 03 '19 at 14:34
  • @MartinBrown - At the time, when I answered that question, `Barrier` wasn't around (June 2019). It appear that it only got introduced in .NET 4.0 which shipped in 2010 (sure there were likely betas and RC's of 4.0, but not really suitable for production code). Having had a look at `Barrier` I'd say you're probably right. I don't have the time to experiment right now, but you could knock up a worked example and I'd happily upvote :) – Kev Apr 03 '19 at 14:53
16

An easy way is to create and start a thread with parameterless lambda:

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

By using this method over ThreadPool.QueueUserWorkItem you can name your new thread to make it easier for debugging. Also, don't forget to use extensive error handling in your routine because any unhandled exceptions outside of a debugger will abruptly crash your application:

enter image description here

josliber
  • 43,891
  • 12
  • 98
  • 133
Robert Venables
  • 5,943
  • 1
  • 23
  • 35
14

The recommended way of doing this when you are using Asp.Net and .Net 4.5.2 is by using QueueBackgroundWorkItem. Here is a helper class:

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

Usage example:

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

or using async:

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

This works great on Azure Web Sites.

Reference: Using QueueBackgroundWorkItem to Schedule Background Jobs from an ASP.NET Application in .NET 4.5.2

Augusto Barreto
  • 3,637
  • 4
  • 29
  • 39
8

Almost 10 years later:

Task.Run(FireAway);

I would add exception handling and logging inside FireAway

Oscar Fraxedas
  • 4,467
  • 3
  • 27
  • 32
7

Calling beginInvoke and not catching EndInvoke is not a good approach. Answer is simple: The reason that you should call EndInvoke is because the results of the invocation (even if there is no return value) must be cached by .NET until EndInvoke is called. For example if the invoked code throws an exception then the exception is cached in the invocation data. Until you call EndInvoke it remains in memory. After you call EndInvoke the memory can be released. For this particular case it is possible the memory will remain until the process shuts down because the data is maintained internally by the invocation code. I guess the GC might eventually collect it but I don't know how the GC would know that you have abandoned the data vs. just taking a really long time to retrieve it. I doubt it does. Hence a memory leak can occur.

More can be found on http://haacked.com/archive/2009/01/09/asynchronous-fire-and-forget-with-lambdas.aspx

  • 3
    The GC can tell when things are abandoned if no reference exists to them. If `BeginInvoke` returns a wrapper object which holds a reference to, but is not referenced by, the object that holds the real result data, the wrapper object would become eligible for finalization once all references to it were abandoned. – supercat Oct 23 '12 at 20:35
  • I question saying this is "not a good approach"; test it, with the error conditions you are concerned about, and see if you have problems. Even if garbage collection is not perfect, it will probably not affect most applications noticeably. Per Microsoft, "You can call EndInvoke to retrieve the return value from the delegate, if neccesary, but this is not required. EndInvoke will block until the return value can be retrieved." from: https://msdn.microsoft.com/en-us/library/0b1bf3y3(v=vs.90).aspx – Abacus Mar 27 '15 at 20:58
5

The simplest .NET 2.0 and later approach is using the Asynchnonous Programming Model (ie. BeginInvoke on a delegate):

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 );  
}
Ash
  • 60,973
  • 31
  • 151
  • 169
3

The simplest way to do fire-and-forget is to use the discard pattern:

_ = MyFireAndForgetTask(myParameters);

This notifies your method that the result of your Task will not be needed and execution of the thread is not stalled.

Please note that the Task must call Task.Run within it to be asynchronous using this pattern. Using our previous method as an example:

Task MyFireAndForgetTask(myParameters)
{
    return Task.Run(/* put Task, Func<T>, or Action here*/);
}

If this step is ignored, the Task will run synchronously and will not behave as expected.

Furthermore the assignment pattern can be used. This is useful for when the method runs until the last line but hangs until the Task is finished. We will utilize Task.Wait() for this. Using our previous method as an example:

void MyCustomEventHandler(object sender, EventArgs args)
{
    /* perform some code here */
    var myTask = MyFireAndForgetTask(myParameters);
    /* perform some more code here; thread is not blocked */

    /// Hang the method until the Task is completed.
    /// using "await myTask;" is equivalent.
    myTask.Wait();
}

This will perform a fire-and-forget-till-completion, which is mandatory on some platforms (i.e. ASP.NET).

  • 1
    But will the task run to completion? The fastest way to ignore a result and to not block the calling thread is to immediately kill the task. This is what happens when hosted, in say ASP.NET. – MatthewMartin Jun 20 '22 at 14:41
  • Great point, I will edit the answer to reflect that along with other points that may be necessary. But if you would like to stall to wait for thread completion after the fire-and-forget, you have to save the object and call TaskObj.Wait() at the end of the method for that thread. –  Jun 21 '22 at 01:48
  • 1
    @MatthewMartin added the edits, let me know if it helped. –  Jun 21 '22 at 02:12
1

If you want to test in Console keep in mind that Console.ReadKey() or something like that is needed before Console loses its thread by Press any key to continue ...

public static void Main()
{
    Task.Factory.StartNew(async () => 
    {
         await LongTaskAsync();         
    }, TaskCreationOptions.LongRunning).ConfigureAwait(false);
    
    Console.WriteLine("Starts immediately");
    Console.ReadKey();
}

static async Task LongTaskAsync()
{
    await Task.Delay(5000);
    Console.WriteLine("After 5 seconds delay");
}
Abuzar G
  • 103
  • 1
  • 4