且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

在 c# 4.0 中执行即发即弃方法的最简单方法

更新时间:2023-11-28 21:38:04

不是 4.0 的答案,但值得注意的是,在 .Net 4.5 中,您可以通过以下方式更简单:

Not an answer for 4.0, but worth noting that in .Net 4.5 you can make this even simpler with:

#pragma warning disable 4014
Task.Run(() =>
{
    MyFireAndForgetMethod();
}).ConfigureAwait(false);
#pragma warning restore 4014

pragma 是禁用警告,告诉您将此任务运行为 fire and forget.

The pragma is to disable the warning that tells you you're running this Task as fire and forget.

如果大括号内的方法返回一个任务:

If the method inside the curly braces returns a Task:

#pragma warning disable 4014
Task.Run(async () =>
{
    await MyFireAndForgetMethod();
}).ConfigureAwait(false);
#pragma warning restore 4014

让我们分解一下:

Task.Run 返回一个 Task,它会生成一个编译器警告(警告 CS4014),指出此代码将在后台运行 - 这正是您想要的,因此我们禁用了警告 4014.

Task.Run returns a Task, which generates a compiler warning (warning CS4014) noting that this code will be run in the background - that's exactly what you wanted, so we disable warning 4014.

默认情况下,Tasks 会尝试Marshal back to the original Thread",这意味着该 Task 将在后台运行,然后尝试返回到启动它的 Thread.通常在原始线程完成后触发并忘记任务完成.这将导致抛出 ThreadAbortException.在大多数情况下,这是无害的——它只是告诉你,我试图重新加入,我失败了,但无论如何你都不在乎.但是,在您的生产日志或本地开发人员的调试器中使用 ThreadAbortExceptions 仍然有点嘈杂..ConfigureAwait(false) 只是一种保持整洁的方式,并明确地说,在后台运行它,就是这样.

By default, Tasks attempt to "Marshal back onto the original Thread," which means that this Task will run in the background, then attempt to return to the Thread that started it. Often fire and forget Tasks finish after the original Thread is done. That will cause a ThreadAbortException to be thrown. In most cases this is harmless - it's just telling you, I tried to rejoin, I failed, but you don't care anyway. But it's still a bit noisy to have ThreadAbortExceptions either in your logs in Production, or in your debugger in local dev. .ConfigureAwait(false) is just a way of staying tidy and explicitly say, run this in the background, and that's it.

由于这很罗嗦,尤其是丑陋的 pragma,我为此使用了一个库方法:

Since this is wordy, especially the ugly pragma, I use a library method for this:

public static class TaskHelper
{
    /// <summary>
    /// Runs a TPL Task fire-and-forget style, the right way - in the
    /// background, separate from the current thread, with no risk
    /// of it trying to rejoin the current thread.
    /// </summary>
    public static void RunBg(Func<Task> fn)
    {
        Task.Run(fn).ConfigureAwait(false);
    }

    /// <summary>
    /// Runs a task fire-and-forget style and notifies the TPL that this
    /// will not need a Thread to resume on for a long time, or that there
    /// are multiple gaps in thread use that may be long.
    /// Use for example when talking to a slow webservice.
    /// </summary>
    public static void RunBgLong(Func<Task> fn)
    {
        Task.Factory.StartNew(fn, TaskCreationOptions.LongRunning)
            .ConfigureAwait(false);
    }
}

用法:

TaskHelper.RunBg(async () =>
{
    await doSomethingAsync();
}