У меня есть пара вопросов с основным ответом на этот вопрос.
Во-первых, в реальной ситуации «запусти и забудь» вы, вероятно, не будете await
задание, поэтому добавлять ConfigureAwait(false)
бесполезно. Если вы не await
значение, возвращаемое ConfigureAwait
, то это не может иметь никакого эффекта.
Во-вторых, вам необходимо знать, что происходит, когда задача завершается с исключением. Рассмотрим простое решение, предложенное @ ade-miller:
Task.Factory.StartNew(SomeMethod); // .NET 4.0
Task.Run(SomeMethod); // .NET 4.5
Это создает опасность: если необработанное исключение выходит за пределы SomeMethod()
, это исключение никогда не будет соблюдено и может 1 быть повторно вызвано в потоке финализатора, что приведет к сбою приложения. Поэтому я бы рекомендовал использовать вспомогательный метод, чтобы обеспечить соблюдение любых возникающих исключений.
Вы могли бы написать что-то вроде этого:
public static class Blindly
{
private static readonly Action<Task> DefaultErrorContinuation =
t =>
{
try { t.Wait(); }
catch {}
};
public static void Run(Action action, Action<Exception> handler = null)
{
if (action == null)
throw new ArgumentNullException(nameof(action));
var task = Task.Run(action); // Adapt as necessary for .NET 4.0.
if (handler == null)
{
task.ContinueWith(
DefaultErrorContinuation,
TaskContinuationOptions.ExecuteSynchronously |
TaskContinuationOptions.OnlyOnFaulted);
}
else
{
task.ContinueWith(
t => handler(t.Exception.GetBaseException()),
TaskContinuationOptions.ExecuteSynchronously |
TaskContinuationOptions.OnlyOnFaulted);
}
}
}
Эта реализация должна иметь минимальные накладные расходы: продолжение вызывается только в том случае, если задача не завершается успешно, и оно должно вызываться синхронно (в отличие от запланированного отдельно от исходной задачи). В «ленивом» случае вам даже не придется выделять делегата продолжения.
Запуск асинхронной операции становится тривиальным:
Blindly.Run(SomeMethod); // Ignore error
Blindly.Run(SomeMethod, e => Log.Warn("Whoops", e)); // Log error
1. Это было поведение по умолчанию в .NET 4.0. В .NET 4.5 поведение по умолчанию было изменено так, что ненаблюдаемые исключения будут не повторно генерироваться в потоке финализатора (хотя вы все равно можете наблюдать их через событие UnobservedTaskException в TaskScheduler). Однако конфигурация по умолчанию может быть переопределена, и даже если вашему приложению требуется .NET 4.5, не следует полагать, что ненаблюдаемые исключения задач будут безвредными.