不是 4.0 的答案,但值得注意的是,在 .Net 4.5 中,您可以通过以下方式使其更简单:
#pragma warning disable 4014
Task.Run(() =>
{
MyFireAndForgetMethod();
}).ConfigureAwait(false);
#pragma warning restore 4014
pragma 是禁用警告,告诉您您正在运行此任务,然后忘记。
如果大括号内的方法返回一个Task:
#pragma warning disable 4014
Task.Run(async () =>
{
await MyFireAndForgetMethod();
}).ConfigureAwait(false);
#pragma warning restore 4014
让我们分解一下:
Task.Run 返回一个任务,它会生成一个编译器警告(警告 CS4014),指出此代码将在后台运行 - 这正是您想要的,因此我们禁用警告 4014。
默认情况下,Tasks 会尝试“Marshal back to the original Thread”,这意味着此 Task 将在后台运行,然后尝试返回启动它的 Thread。通常在原始线程完成后触发并忘记任务完成。这将导致抛出 ThreadAbortException。在大多数情况下,这是无害的——它只是告诉你,我试图重新加入,但我失败了,但无论如何你都不在乎。但是,无论是在生产日志中,还是在本地开发者的调试器中,都有 ThreadAbortExceptions 仍然有点吵。 .ConfigureAwait(false) 只是保持整洁的一种方式,明确地说,在后台运行它,就是这样。
由于这很罗嗦,尤其是丑陋的杂注,我为此使用了一个库方法:
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();
}