2013-10-26 2 views
0

.NET에서 제공자 모델 패턴을 사용하는 작은 응용 프로그램을 작성하고 있습니다. 각 프로 바이더에는, 어플리케이션으로 플러그 인하기 위해서 구현하는 1 개의 메소드가 있습니다.C# async, 코드에 액세스하지 않고 작업이 완료되면 모든 작업을 중지하십시오.

모든 공급자의 특정 작업 (구현 된 메서드)을 다른 스레드에서 실행하려고하지만 하나의 작업이 완료되면 다른 모든 작업이 실행을 중지해야합니다.

.NET에서 async/await 모델을 사용하여 CancellationToken을 사용하여 작업을 취소합니다.

tasks.Add(Task.Run(() => 
       { 
         if (token.IsCancellationRequested) 
          token.ThrowIfCancellationRequested(); 

         return provider.DoWork(); 

       }, token)); 

while (tasks.Count > 0) 
     { 
      var t = await Task.WhenAny(tasks); 

      tasks.Remove(t); 

      var result = await t; 

      if (!string.IsNullOrEmpty(result)) 
      { 
       tokenSource.Cancel(); 
       return result; 
      } 
     } 

provider.DoWork의 일부

() 메소드는 매우 느릴 수 있습니다 및 DoWork 방법은 내가 DoWork 방법 내에서 token.IsCancellationRequested을 확인해야 실행되는 스레드를 중지하지만이 방법은 기록 할 수 없기 때문에 예를 들어, 다른 누군가로부터. 토큰 검사. DoWork 외부로의 요청 취소는 그럴 경우 중요하지 않습니다.

요약하면 하나의 작업이 끝나면 다른 작업을 중지해야하지만 각 스레드에서 실행중인 코드에 액세스 할 필요가 없습니다.

당신의 생각을 듣고 싶습니다.

+1

"가장 빠른 공급자가 이긴다"는 이상한 모델입니다. –

+1

제공자가 협조적이며 주기적으로 취소 토큰을 확인할 수 없다면 작성해야 할 것으로 의심됩니다. 코드는 공급자의 스레드를 관리하고 중지하려는 공급자의 스레드를 중단/중단합니다. –

+0

@MarcGravell 공급자가 뭔가를 검색하는 html 파서 (html 파서) 중 하나가 사이트를 찾았을 때 다른 사이트에서 5 ~ 10 초 동안 응답을 기다리는 경우 왜 10 초를 기다려야하는지 생각해보십시오. 사실 그 코드를 사용하면 (클라이언트로서) 검색 결과가 표시되지만 작업이 종료되지 않으며 CPU가 100 % 불필요합니다. –

답변

0

임의의 코드를 중지하는 여러 가지 가능한 방법이 있으며 그 중 어떤 것도 이상적이지 않습니다.

먼저 스레드 수준에서이를 접근 할 수 있습니다. 즉, 각 공급자에게 별도의 스레드를 제공하고 중지하려는 경우 Thread.Abort으로 전화하십시오. 불행하게도이 접근법에는 많은 문제가 있습니다. 두 가지 더 잘 알려진 문제는 교착 상태가 발생할 수 있으며 AppDomain에서 유형을 더 이상 인스턴스화 할 수없는 이상한 상태로 들어갈 수 있다는 것입니다. 이러한 이유 때문에 Thread.Abort은 "악의적 인"것으로 간주되어 명확한 코드의 냄새가납니다.

한 단계 위로 이동하면 AppDomain 수준에서이 값에 접근 할 수 있습니다. 이 경우 각 공급자에게 별도의 AppDomain을 제공합니다. 이 접근법의 장점은 스레드보다 더 깔끔하게 AppDomain을 종료 할 수 있다는 것입니다. 불행하게도 여전히 균열을 헤쳐 나갈 수있는 요소가 있습니다. 특히 관리되지 않는 리소스가 AppDomain에서 프로세스로 누출 될 수 있습니다.

가장 신뢰할 수있는 솔루션으로 남겨 둡니다. 프로세스 수준에서이를 해결합니다. 즉, 각 공급자에게 별도의 프로세스를 제공하고 프로세스 간 통신을 사용하여이를 제어합니다. OS가 정리를 담당하기 때문에 프로세스를 정상적으로 종료 할 수 있습니다. 불행히도이 접근법은 오버 헤드가 가장 많으며 프로그램하기가 가장 어렵습니다.

견고한 호스팅 솔루션은 최소한 마지막 호스팅 솔루션을 지원해야합니다. 예를 들어, ASP.NET은 세 가지를 모두 지원합니다. 일부 상황 (예 : 클라이언트의 연결이 끊어짐)에서 요청 스레드를 중단하고 AppDomain을 재활용 할 수 있으며 전체 작업자 프로세스가 재활용되는 곳으로 에스컬레이션됩니다.그러나 에스컬레이션 정책이 포함 된 자체 호스팅 플랫폼을 작성하지 않는 것이 좋습니다.

1) 제공자에게 CancellationToken을 제공하고 사용하도록 권장하고, 2) 토큰에 신호를 보내고 나면 완료되도록 실행하는 것이 좋습니다.

+0

자세한 답변을 부탁드립니다. CancellationToken을 공급자에게 전달하는 것에 대한 나의 주요 관심사는 다음과 같습니다. 1) 공급자가 구현 된 방법과 실행 된 컨텍스트 (비동기, 동기화 등) 사이에 일종의 연결을 만드는 방식입니다. 2) 제공 업체는 CancellationToken의 정의와 사용 방법을 알아야합니다. 3) Token을 적절히 다루지 않는 제공자는 전체 시스템을 느리게 할 수 있습니다 (솔루션 : @Marc의 말처럼 - 느린 제공자를 무시하거나 어떤 종류의 타임 아웃을 설정합니다). 다른 한편, 외부 라이브러리 또는 API를 사용하는 경우이를 사용하는 방법을 알아야합니다. –

+0

나는 당신이 무엇을 의미하는지 모르겠습니다 (1); 'CancellationToken'은 동기 코드와 비동기 코드의 표준 취소 메카니즘입니다. 나는 (2)가 어려운 제안은 아니라고 생각한다. 그리고 (3)까지, 어리석은 코드를 관리하는 유일한 방법은 별도의 과정입니다. –

2

프로세스에서 스레드를 갑작스럽게 종료하는 것과 관련된 많은 문제가 있습니다. 프로세스가 너무 아파서 어쨌든 전체를 죽이려고 할 때 최후의 수단으로 만 수행해야합니다. 그 이외의 것, 그리고 방해를 받으면 중대한 문제를 일으킬 수있는 중대한 위험에 처해 있습니다. 그래서 : 그것은 유익한 선택적인 출구를 떠난다. 이미 취소 토큰을 사용하고 있다고 언급했습니다. 정말로, 그게 당신이 할 수있는 전부입니다 (적어도, 안전하게). 취소 및 종료를 확인하는 것은 다른 구현에 달려 있습니다. 주기적으로 취소를 확인하는 작업에 의존 할 수 없다면 약간 방해가됩니다.

기본적으로 설명하는 내용에 대한 쉬운 대답은 없습니다.

관련 문제