在C#中最简单的方法来做一个消防和遗忘的方法?

我在WCF看到他们有[OperationContract(IsOneWay = true)]属性。 但是WCF似乎有点缓慢和沉重,只是为了创build一个非阻塞函数。 理想情况下,会有像静态无MethodFoo(){} ,但我不认为这存在。

在C#中创build非阻塞方法调用的最快方法是什么?

例如

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

注意 :每个人都应该考虑一下,如果他们真的想要完成这个方法的话。 (请参阅#2最佳答案)如果方法必须完成,那么在某些地方,如ASP.NET应用程序,您将需要执行一些操作来阻止并保持线程处于活动状态。 否则,这可能导致“遗忘但从未实际执行”,在这种情况下,根本不写任何代码会更简单。 ( 这是如何在ASP.NET中工作的一个很好的描述 )

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

(五年后…)

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

正如luisperezphd所指出的那样 。

对于C#4.0以及更新的版本,现在Ade Miller给出了最好的答案: 最简单的方法是在c#4.0中执行fire and forget方法

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

甚至…

 Task.Factory.StartNew(FireAway); 

要么…

 new Task(FireAway).Start(); 

FireAway在哪里FireAway

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

所以凭借类和方法的名称简洁,这取决于你select的一个在六到十九个字符之间击败线程池版本:)

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

要添加到Will的答案 ,如果这是一个控制台应用程序,只需引入一个AutoResetEvent和一个WaitHandle以防止在工作线程完成之前退出:

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

一个简单的方法是创build一个无参数lambda的线程:

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

通过在ThreadPool.QueueUserWorkItem上使用这个方法,你可以为你的新线程命名,以便于debugging。 另外,不要忘记在例程中使用广泛的error handling,因为debugging器外部的任何未处理的exception都会突然崩溃应用程序:

在这里输入图像说明

对于.NET 4.5:

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

调用beginInvoke并不捕获EndInvoke不是一个好方法。 答案很简单:你应该调用EndInvoke的原因是因为调用的结果(即使没有返回值)必须被.NETcaching,直到EndInvoke被调用。 例如,如果被调用的代码抛出一个exception,那么这个exception被caching在调用数据中。 直到你调用EndInvoke,它仍然在内存中。 在调用EndInvoke之后,可以释放内存。 对于这种特殊情况,内存可能会一直保留,直到进程closures,因为数据由调用代码在内部维护。 我想GC可能最终收集它,但我不知道如何GC会知道你已经放弃了数据,而只是花了很长的时间来检索它。 我怀疑这是否。 因此可能会发生内存泄漏。

更多可以在http://haacked.com/archive/2009/01/09/asynchronous-fire-and-forget-with-lambdas.aspx上find

当你使用Asp.Net和.Net 4.5.2时,推荐的方法是使用QueueBackgroundWorkItem 。 这是一个帮手类:

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

用法示例:

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

或使用asynchronous:

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

这在Azure网站上效果很好。

参考: 使用QueueBackgroundWorkItem在.NET 4.5.2中从ASP.NET应用程序调度后台作业

最简单的.NET 2.0及更高版本的方法是使用Asynchnonous编程模型(即委托上的BeginInvoke):

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