Простой способ сделать огонь и забыть метод в C#?


Я видел в WCF у них

9 116

9 ответов:

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

(пять лет спустя...)

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

Как указал luisperezphd.

для C# 4.0 и новее, мне кажется, что лучший ответ теперь дается здесь Аде Миллер:самый простой способ сделать огонь и забыть метод в c# 4.0

Task.Factory.StartNew(() => FireAway());

или даже...

Task.Factory.StartNew(FireAway);

или...

new Task(FireAway).Start();

здесь FireAway и

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

таким образом, в силу класса и имени метода краткость это бьет версия threadpool от шести до девятнадцати символов в зависимости от тот, который вы выберете :)

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

добавить Уилл!--5-->, если это консольное приложение, просто выбросить в 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();
    }
}

для .NET 4.5:

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

простой способ-создать и запустить поток с параметрической лямбда:

(new Thread(() => { 
    FireAway(); 
    MessageBox.Show("FireAway Finished!"); 
}) { 
    Name = "Long Running Work Thread (FireAway Call)",
    Priority = ThreadPriority.BelowNormal 
}).Start();

С помощью этого метода над ThreadPool.QueueUserWorkItem вы можете назвать свой новый поток, чтобы упростить его отладку. Кроме того, не забудьте использовать обширную обработку ошибок в своей рутине, потому что любые необработанные исключения за пределами отладчика резко разрушат ваше приложение:

enter image description here

рекомендуемый способ сделать это, когда вы используете 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();
});

или с помощью async:

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

это отлично работает на веб-сайтах Azure.

ссылки: использование QueueBackgroundWorkItem для планирования фоновых заданий ASP.NET применение в .NET 4.5.2

вызов beginInvoke и не поймать EndInvoke не является хорошим подходом. Ответ прост: Причина, по которой Вы должны вызвать EndInvoke, заключается в том, что результаты вызова (даже если нет возвращаемого значения) должны быть кэшированы .NET до вызова EndInvoke. Например, если вызванный код вызывает исключение, то исключение кэшируется в данных вызова. Пока вы не вызовете EndInvoke, он остается в памяти. После вызова EndInvoke память может быть освобождена. Для этого если это возможно, память останется до тех пор, пока процесс не завершится, потому что данные поддерживаются внутренне кодом вызова. Я думаю, что GC может в конечном итоге собрать его, но я не знаю, как GC узнает, что вы отказались от данных, а просто взяли очень много времени, чтобы получить его. Я сомневаюсь, что он делает. Следовательно, может произойти утечка памяти.

другое можно найти на http://haacked.com/archive/2009/01/09/asynchronous-fire-and-forget-with-lambdas.aspx

самый простой .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 );  
}

почти 10 лет спустя:

Task.Run(FireAway);

Я бы добавил обработку исключений и войдя внутрь стреляй