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