Я хочу запустить задачу в фоновом потоке. Не хочу ждать завершения задач.
В .net 3.5 я бы сделал это:
ThreadPool.QueueUserWorkItem(d => { DoSomething(); });
В .net 4 рекомендуется использовать TPL. Я видел рекомендуемый общий шаблон:
Task.Factory.StartNew(() => { DoSomething(); });
Однако StartNew()
метод возвращает Task
объект, который реализует IDisposable
. Похоже, что люди, рекомендующие этот шаблон, не замечают этого. В документации MSDN по этому Task.Dispose()
методу говорится:
«Всегда вызывайте Dispose перед тем, как отпустить последнюю ссылку на Задачу».
Вы не можете вызвать dispose для задачи, пока она не будет завершена, поэтому ожидание основного потока и вызов dispose в первую очередь нарушит точку выполнения в фоновом потоке. Также, похоже, нет никакого завершенного / завершенного события, которое можно было бы использовать для очистки.
На странице MSDN в классе Task это не комментируется, а книга «Pro C # 2010 ...» рекомендует тот же шаблон и не дает никаких комментариев по удалению задач.
Я знаю, что если я просто оставлю это, финализатор поймает его в конце, но вернется ли он и укусит меня, когда я выполняю много задач типа «огонь и забывай», и поток финализатора будет перегружен?
Итак, мои вопросы:
- Приемлемо ли не звонить
Dispose()
поTask
классу в этом случае? И если да, то почему и существуют ли риски / последствия? - Есть ли документация, в которой это обсуждается?
- Или есть подходящий способ избавиться от
Task
предмета, который я пропустил? - Или есть другой способ выполнить задачи «выстрелил и забыл» с TPL?
источник
Ответы:
Об этом обсуждают на форумах MSDN .
Стивен Туб, член команды Microsoft pfx, сказал следующее:
Обновление (октябрь 2012 г.)
Стивен Туб опубликовал блог под названием « Нужно ли мне избавляться от задач?» который дает более подробную информацию и объясняет улучшения в .Net 4.5.
Подводя итог: вам не нужно избавляться от
Task
предметов в 99% случаев.Есть две основные причины для удаления объекта: своевременное и детерминированное освобождение неуправляемых ресурсов и избежание затрат на запуск финализатора объекта. Ни то, ни другое не применимо в
Task
большинстве случаев:Task
выделяет внутренняя ручка ожидания (только неуправляемый ресурс вTask
объекте), когда вы явно использоватьIAsyncResult.AsyncWaitHandle
изTask
, иTask
объект не имеет финализатора; дескриптор сам заключен в объект с финализатором, поэтому, если он не выделен, финализатор не запускается.источник
EndInvoke
в WinForms при использованииBeginInvoke
для запуска кода в потоке пользовательского интерфейса). (2) Стивен Тауб хорошо известен как постоянный докладчик по эффективному использованию PFX (например, на channel9.msdn.com ), так что если кто-то может дать хорошее руководство, то он его. Обратите внимание на его второй абзац: временами лучше оставить дело финализатору.Это та же проблема, что и с классом Thread. Он использует 5 дескрипторов операционной системы, но не реализует IDisposable. Хорошее решение исходных дизайнеров, конечно, есть несколько разумных способов вызвать метод Dispose (). Сначала вам нужно вызвать Join ().
Класс Task добавляет к этому один дескриптор - внутреннее событие ручного сброса. Какой ресурс операционной системы самый дешевый. Конечно, его метод Dispose () может освободить только этот один дескриптор события, а не 5 дескрипторов, которые использует Thread. Да, не беспокойтесь .
Помните, что вас должно интересовать свойство IsFaaled задачи. Это довольно неприятная тема, вы можете прочитать о ней в этой статье библиотеки MSDN . Как только вы справитесь с этим должным образом, у вас также должно быть хорошее место в вашем коде для размещения задач.
источник
Thread
в большинстве случаев задача не создает объект , а использует ThreadPool.Мне бы очень хотелось, чтобы кто-то оценил технику, показанную в этом посте: Типичный вызов асинхронного делегата типа «выстрелил и забыл» в C #
Похоже, что простой метод расширения будет обрабатывать все тривиальные случаи взаимодействия с задачами и сможет вызывать для него dispose.
источник
Task
экземпляра, возвращенногоContinueWith
, но, как видите, цитата из Стивена Туба является принятым ответом: нечего удалять, если ничто не выполняет блокирующее ожидание для задачи.Task disper = null; disper = tsk.ContinueWith(cnt => { cnt.Dispose(); disper.Dispose(); });