백그라운드 스레드에서 실행되는 작업을 트리거하고 싶습니다. 작업 완료를 기다리고 싶지 않습니다.
.net 3.5에서이 작업을 수행했을 것입니다.
ThreadPool.QueueUserWorkItem(d => { DoSomething(); });
넷에서 TPL은 제안 된 방법입니다. 추천 된 일반적인 패턴은 다음과 같습니다.
Task.Factory.StartNew(() => { DoSomething(); });
그러나, 그StartNew()
메서드는Task
구현하는 객체IDisposable
. 이
이 패턴을 추천하는 사람들이 간과하는 것처럼 보인다. MSDN 문서Task.Dispose()
방법 말한다 :
"작업에 대한 마지막 참조를 해제하기 전에 항상 Dispose에 전화하십시오."
작업이 완료 될 때까지 dispose를 호출 할 수 없으므로 주 스레드 대기 및 호출 처 리를 수행하면 처음부터 백그라운드 스레드에서 수행 지점을 무력화 할 수 있습니다. 또한 정리에 사용할 수있는 완료 / 완료 이벤트가없는 것 같습니다.
Task 클래스의 MSDN 페이지는 이에 대해 언급하지 않고 "Pro C #2010 ..."책은 동일한 패턴을 권장하고 작업 처리에 대해서는 언급하지 않습니다.
내가 방금 종료자를 남겨두면 최종적으로 그것을 잡을 것입니다. 그러나 이것은 많은 불 &을하고있을 때 되돌아 와서 물러 설 것입니다. 이와 같은 작업을 잊어 버리면 파이널 라이저 스레드가 당황합니까?
그래서 내 질문은 :
Dispose()
~에Task
이 경우 클래스? 그렇다면 왜 위험과 결과가 있습니까?Task
내가 놓친 물건?
이것에 대한 토론이 있습니다.MSDN 포럼.
Microsoft pfx 팀원 인 Stephen Toub은 다음과 같이 말합니다.
작업으로 인해 Task.Dispose가 존재합니다. 잠재적으로 이벤트 핸들을 래핑 작업을 기다릴 때 사용됩니다. 완료, 대기중인 경우 스레드가 실제로 차단해야합니다 ( 회전이나 잠재적으로 대기중인 작업 실행). 네가하는 모든 일이 그 이벤트 핸들은 결코 할당되지 않는다.
...
상황을 처리하기 위해 최종 결정에 의존하는 것이 좋습니다.
업데이트 (2012 년 10 월)
Stephen Toub은 제목이 블로그를 게시했습니다.할 일 목록을 처리해야합니까?좀 더 자세한 내용을 제공하고 .Net 4.5의 개선점을 설명합니다.
요약하면 다음을 처리 할 필요가 없습니다.Task
개체의 99 %.
개체를 처리하는 주된 이유는 두 가지입니다. 관리되지 않는 리소스를 적시에 결정적으로 확보하고 개체의 최종 자 도구를 실행하는 데 드는 비용을 피하십시오. 이들 중 어느 것도Task
대부분의 시간 :
Task
내부 대기 핸들을 할당합니다.Task
개체)는 명시 적으로IAsyncResult.AsyncWaitHandle
~의Task
, 및Task
객체 자체에는 파이널 라이저가 없습니다. 핸들 자체는 파이널 라이저를 사용하여 객체에 래핑되므로 할당되어 있지 않으면 실행할 파이널 라이저가 없습니다.EndInvoke
사용하는 경우 WinForms에서BeginInvoke
UI 스레드에서 코드를 실행). (2) Stephen Toub은 PFX를 효과적으로 사용하는 데 대한 일반 연사로 잘 알려져 있습니다 (예 : onchannel9.msdn.com), 그래서 누군가가 좋은 지침을 줄 수 있다면 그는 그것입니다. 두 번째 단락을 주목하십시오 : 최종 자에게 물건을 남기는 것이 더 낫습니다. - Richard
이것은 Thread 클래스와 같은 종류의 문제이다. 5 개의 운영 체제 핸들을 사용하지만 IDisposable은 구현하지 않습니다. 원래 디자이너의 결정에 따라 Dispose () 메소드를 호출하는 합리적인 방법은 거의 없습니다. 먼저 Join ()을 호출해야합니다.
Task 클래스는 하나의 핸들을 내부 수동 재설정 이벤트로 추가합니다. 가장 저렴한 운영 체제 리소스가 있습니다. 물론 Dispose () 메서드는 Thread가 소비하는 5 개의 핸들이 아니라 하나의 이벤트 핸들 만 릴리스 할 수 있습니다.그래, 신경 안써..
작업의 IsFaulted 속성에 관심을 가져야한다는 것을 유의하십시오. 그것은 꽤 추악한 주제입니다, 당신은 이것에 대해 더 많은 것을 읽을 수 있습니다.MSDN Library 기사. 이 문제를 적절하게 처리하면 코드에서 작업을 처리하기에 좋은 자리를 가져야합니다.
Thread
대부분의 경우 ThreadPool을 사용합니다. - svick
이 게시물에 표시된 기술에 누군가가 무게가 나는 것을보고 싶습니다.C #에서 형식 보증 된 비동기 대리자 호출
간단한 확장 메소드가 태스크와 상호 작용하는 모든 사소한 경우를 처리하고 태스크를 처리 할 수있는 것처럼 보입니다.
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());
}
Task
에 의해 반환 된 인스턴스ContinueWith
,하지만 Stephen Toub의 인용문은 받아 들여진 대답입니다. 아무 것도 작업 대기를 차단하지 않으면 처분 할 것이 없습니다. - RichardTask disper = null; disper = tsk.ContinueWith(cnt => { cnt.Dispose(); disper.Dispose(); });
- Gideon Engelberth