IT박스

TPL Task 객체에서 Dispose ()를 호출하지 않는 것이 허용됩니까?

itboxs 2020. 7. 20. 07:52
반응형

TPL Task 객체에서 Dispose ()를 호출하지 않는 것이 허용됩니까?


백그라운드 스레드에서 작업을 실행하도록 트리거하고 싶습니다. 작업 완료를 기다리고 싶지 않습니다.

.net 3.5에서는이 작업을 수행했을 것입니다.

ThreadPool.QueueUserWorkItem(d => { DoSomething(); });

.net 4에서는 TPL이 권장되는 방법입니다. 내가 보았던 일반적인 패턴은 다음과 같습니다.

Task.Factory.StartNew(() => { DoSomething(); });

그러나이 StartNew()메서드는를 Task구현 하는 개체를 반환합니다 IDisposable. 이 패턴을 추천하는 사람들이 간과하는 것 같습니다. Task.Dispose()방법 에 대한 MSDN 설명서 는 다음과 같이 말합니다.

"작업에 대한 마지막 참조를 해제하기 전에 항상 Dispose에 전화하십시오."

작업이 완료 될 때까지 작업에서 dispose를 호출 할 수 없으므로 기본 스레드 대기 및 호출 dispose를 사용하면 처음부터 백그라운드 스레드에서 수행하는 지점을 물리 칠 수 있습니다. 또한 정리에 사용될 수있는 완료 / 완료된 이벤트가없는 것 같습니다.

Task 클래스의 MSDN 페이지는 이에 대해 언급하지 않으며 "Pro C # 2010 ..."책은 동일한 패턴을 권장하며 작업 처리에 대해서는 언급하지 않습니다.

파이널 라이저가 결국에는 그것을 잡을 수 있다는 것을 알고 있지만, 많은 불을 피우거나 이와 같은 작업을 잊어 버리고 파이널 라이저 스레드가 압도 될 때 이것이 다시 돌아와서 물 릴까요?

그래서 내 질문은 :

  • 그것은 호출하지 받아 들일 Dispose()Task이 경우 클래스? 그렇다면, 왜 그리고 위험 / 결과가 있습니까?
  • 이에 대해 설명하는 문서가 있습니까?
  • 아니면 Task내가 놓친 물건을 처분하는 적절한 방법이 있습니까?
  • 아니면 TPL로 화재를 피하고 작업을 잊는 다른 방법이 있습니까?

MSDN 포럼에서 이에 대한 토론이 있습니다 .

Microsoft pfx 팀의 구성원 인 Stephen Toub는 다음과 같이 말합니다.

Task.Dispose는 작업이 완료 될 때까지 대기 할 때 사용 된 이벤트 핸들을 잠재적으로 래핑하는 작업으로 인해 대기중인 스레드가 실제로 차단하거나 대기중인 작업을 실행하는 것과는 반대로 차단해야하는 경우에 존재합니다. 당신이하고있는 모든 것이 연속을 사용하고 있다면, 그 이벤트 핸들은 할당되지 않을 것입니다
...
마무리에 의존하여 일을 처리하는 것이 좋습니다.

업데이트 (2012 년 10 월)
Stephen Toub가 작업을 처리해야합니까? 라는 제목의 블로그를 게시했습니다 . 좀 더 자세하게 설명하고 .Net 4.5의 개선 사항을 설명합니다.

요약 : Task99 %의 시간 동안 물체 를 폐기 할 필요가 없습니다 .

개체를 폐기해야하는 두 가지 주요 이유는 관리되지 않은 리소스를시기 적절하고 결정적인 방식으로 해제하고 개체의 종료자를 실행하는 비용을 피하는 것입니다. 이들 중 어느 것도 Task대부분의 시간에 적용되지 않습니다 :

  1. .Net 4.5부터는 Task내부 대기 핸들 ( Task객체 에서 관리되지 않는 유일한 리소스)을 할당 하는 유일한 시간 IAsyncResult.AsyncWaitHandleTask, 및
  2. Task객체 자체는 종료자가 없습니다; 핸들 자체는 종료자를 사용하여 객체로 래핑되므로 할당되지 않으면 실행할 종료자가 없습니다.

이것은 Thread 클래스와 같은 종류의 문제입니다. 5 개의 운영 체제 핸들을 사용하지만 IDisposable을 구현하지 않습니다. 원래 디자이너의 결정은 물론 Dispose () 메서드를 호출하는 합리적인 방법은 거의 없습니다. 먼저 Join ()을 호출해야합니다.

Task 클래스는 내부 수동 재설정 이벤트 인 핸들 하나를 추가합니다. 가장 저렴한 운영 체제 리소스는 어느 것입니까? 물론 Dispose () 메서드는 Thread가 사용하는 5 개의 핸들이 아니라 하나의 이벤트 핸들 만 해제 할 수 있습니다. 예, 귀찮게하지 마십시오 .

작업의 IsFaulted 속성에 관심을 가져야합니다. 상당히 추악한 주제 입니다. MSDN Library 기사 에서 자세한 내용을 읽을 수 있습니다 . 이 문제를 올바르게 해결하면 코드를 통해 작업을 처리 할 수있는 좋은 위치에 있어야합니다.


누군가 가이 게시물에 표시된 기술에 무게를 두는 것을보고 싶습니다 : C #에서 Typesafe fire-and-forget 비동기 델리게이트 호출

간단한 확장 방법은 작업과 상호 작용하는 모든 사소한 경우를 처리하고 처리를 호출 할 수있는 것처럼 보입니다.

public static void FireAndForget<T>(this Action<T> act,T arg1)
{
    var tsk = Task.Factory.StartNew( ()=> act(arg1),
                                     TaskCreationOptions.LongRunning);
    tsk.ContinueWith(cnt => cnt.Dispose());
}

참고 URL : https://stackoverflow.com/questions/3734280/is-it-considered-acceptable-to-not-call-dispose-on-a-tpl-task-object

반응형