Simplest way to do a fire and forget method in C#?

C#.NetNonblocking

C# Problem Overview


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)

C# Solutions


Solution 1 - C#

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

(five years later...)

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

as pointed out by luisperezphd.

Solution 2 - C#

For C# 4.0 and newer, it strikes me that the best answer is now given here by Ade Miller: https://stackoverflow.com/questions/5613951/simplest-way-to-do-a-fire-and-forget-method-in-c-sharp-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());

Solution 3 - C#

For .NET 4.5:

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

Solution 4 - C#

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

Solution 5 - C#

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

Solution 6 - C#

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

Solution 7 - C#

Almost 10 years later:

Task.Run(FireAway);

I would add exception handling and logging inside FireAway

Solution 8 - C#

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

Solution 9 - C#

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

Solution 10 - C#

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMatthewMartinView Question on Stackoverflow
Solution 1 - C#user1228View Answer on Stackoverflow
Solution 2 - C#Patrick SzalapskiView Answer on Stackoverflow
Solution 3 - C#David MurdochView Answer on Stackoverflow
Solution 4 - C#KevView Answer on Stackoverflow
Solution 5 - C#Robert VenablesView Answer on Stackoverflow
Solution 6 - C#Augusto BarretoView Answer on Stackoverflow
Solution 7 - C#Oscar FraxedasView Answer on Stackoverflow
Solution 8 - C#Manoj AggarwalView Answer on Stackoverflow
Solution 9 - C#AshView Answer on Stackoverflow
Solution 10 - C#Abuzar GView Answer on Stackoverflow