Простой способ сделать огонь и забыть метод в C#?
Я видел в WCF у них
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(); } }
простой способ-создать и запустить поток с параметрической лямбда:
(new Thread(() => { FireAway(); MessageBox.Show("FireAway Finished!"); }) { Name = "Long Running Work Thread (FireAway Call)", Priority = ThreadPriority.BelowNormal }).Start();
С помощью этого метода над ThreadPool.QueueUserWorkItem вы можете назвать свой новый поток, чтобы упростить его отладку. Кроме того, не забудьте использовать обширную обработку ошибок в своей рутине, потому что любые необработанные исключения за пределами отладчика резко разрушат ваше приложение:
рекомендуемый способ сделать это, когда вы используете 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.
вызов 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 ); }