在 C# 中执行即发即弃方法的最简单方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1018610/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 05:39:45  来源:igfitidea点击:

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

c#.netnonblocking

提问by MatthewMartin

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.

我在 WCF 中看到他们有这个[OperationContract(IsOneWay = true)]属性。但是 WCF 似乎有点缓慢而繁重,只是为了创建一个非阻塞函数。理想情况下会有像 static void nonblocking 这样的东西MethodFoo(){},但我认为不存在。

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

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

注意:阅读本文的每个人都应该考虑他们是否真的希望该方法完成。(请参阅#2 top answer)如果该方法必须完成,那么在某些地方,例如 ASP.NET 应用程序,您将需要执行一些操作来阻止并保持线程处于活动状态。否则,这可能会导致“fire-forget-but-never-actually-execute”,在这种情况下,当然,根本不写代码会更简单。(很好地描述了这是如何在 ASP.NET 中工作的

采纳答案by MatthewMartin

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

(five years later...)

(五年后...)

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

as pointed out by luisperezphd.

正如luisperezphd所指出的。

回答by Robert Venables

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

一种简单的方法是使用无参数 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:

通过在 ThreadPool.QueueUserWorkItem 上使用此方法,您可以命名新线程以使其更易于调试。另外,不要忘记在您的例程中使用大量错误处理,因为调试器之外的任何未处理的异常都会使您的应用程序突然崩溃:

enter image description here

在此处输入图片说明

回答by Kev

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

要添加到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();
    }
}

回答by Ash

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

最简单的 .NET 2.0 及更高版本的方法是使用异步编程模型(即委托上的 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 );  
}

回答by Manoj Aggarwal

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.

调用 beginInvoke 而不是捕获 EndInvoke 不是一个好方法。答案很简单:您应该调用 EndInvoke 的原因是因为调用的结果(即使没有返回值)必须由 .NET 缓存,直到调用 EndInvoke。例如,如果调用的代码抛出异常,则该异常将缓存在调用数据中。在您调用 EndInvoke 之前,它一直保留在内存中。调用 EndInvoke 后,可以释放内存。对于这种特殊情况,内存可能会一直保留到进程关闭,因为数据是由调用代码在内部维护的。我猜 GC 最终可能会收集它,但我不知道 GC 如何知道您已经放弃了数据,而不是花费很长时间来检索它。我怀疑它确实如此。因此可能会发生内存泄漏。

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

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

回答by Patrick Szalapski

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

对于 C# 4.0 和更新版本,我觉得最好的答案现在由 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 FireAwayis

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());
Task.Factory.StartNew(() => FireAway());

甚至...

Task.Factory.StartNew(FireAway);

或者...

new Task(FireAway).Start();

哪里FireAway

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

因此,凭借类和方法名称的简洁性,这比线程池版本高 6 到 19 个字符,具体取决于您选择的那个:)

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

回答by David Murdoch

For .NET 4.5:

对于 .NET 4.5:

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

回答by Augusto Barreto

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:

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

Usage example:

用法示例:

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

or using async:

或使用异步:

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

This works great on Azure Web Sites.

这在 Azure 网站上非常有效。

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

参考:使用 QueueBackgroundWorkItem 从 .NET 4.5.2 中的 ASP.NET 应用程序安排后台作业

回答by Oscar Fraxedas

Almost 10 years later:

近10年后:

Task.Run(FireAway);

I would add exception handling and logging inside FireAway

我会在 FireAway 中添加异常处理和日志记录