2010-08-03 6 views
4

웹 서비스를 클라이언트에 노출시키는 간단한 서버에서 작업하고 있습니다. 일부 요청은 완료하는 데 시간이 오래 걸리고 논리적으로 여러 단계로 나뉩니다. 이러한 요청의 경우 실행 중 진행 상황을보고해야합니다. 또한 이전 요청이 완료되기 전에 새 요청이 시작될 수 있으며 두 시스템이 동시에 실행해야합니다 (일부 시스템 관련 제한 사항 제외).다중 단계 작업의 진행 상태 추적

나는 서버가 TaskId를 클라이언트에 반환하고 클라이언트가 TaskId를 사용하여 요청 진행 상황을 추적하도록하는 방법을 고려하고있었습니다. 나는 이것이 좋은 접근 방법이라고 생각하며, 나는 어떻게 업무가 관리되는지에 관한 문제로 남겨져있다.

TPL을 절대로 사용하지 않은 것이이 문제에 접근하는 좋은 방법이라고 생각했습니다. 실제로 스레드를 수동으로 관리 할 필요없이 여러 작업을 동시에 실행할 수 있습니다. ContinueWith를 사용하여 비교적 쉽게 여러 단계 작업을 만들 수도 있습니다.

그러나 나는 작업 진행 상황을 추적하는 좋은 방법을 생각해 내지 못합니다. 내 요청이 단일 "단계"로 구성되어있는 경우 협력 단계에서 상태를보고해야한다는 것을 알고 있습니다. 이것은 내가 지금 피하려고하는 것이 좋습니다. 그러나 요청이 여러 단계로 구성되어있는 경우 어떤 단계가 현재 실행 중인지 알고 그에 따라 진행 상황을보고하고 싶습니다.

Task<int> firstTask = new Task(() => { DoFirstStep(); return 3.14; }); 
firstTask. 
ContinueWith<int>(task => { UpdateProgress("50%"); return task.Result; }). 
ContinueWith<string>(task => { DoSecondStep(task.Result); return "blah"; }. 
ContinueWith<string>(task => { UpdateProgress("100%"); return task.Result; }). 

그리고 대신의 UpdateProgress 일부 알려진 위치를 업데이트 할 필요없이, 자신의 진행 상황을 저장하는 작업을하고 싶은 이후에도이 완벽하지 : 내가 가지고 올 수있는 유일한 방법은 매우 귀찮은이다. 게다가 새로운 단계를 추가 할 때 많은 장소를 변경해야한다는 명백한 단점이 있습니다 (지금부터 진행률은 50 %, 100 % 대신 33 %, 66 %, 100 %입니다).

누구에게 좋은 해결책이 있습니까?

감사합니다.

답변

4

을이 정말 작업 당신이 큐에 업데이트를 진행하고 다른 작업에 읽을 공급 곳 완전히

당신은 접근 방식을 고려해 볼 수 있습니다 도서관 지원 병렬 시나리오가 아닙니다.. :

static void Main(string[] args) 
{ 
    Example(); 
} 

static BlockingCollection<Tuple<int, int, string>> _progressMessages = 
    new BlockingCollection<Tuple<int, int, string>>(); 

public static void Example() 
{ 
    List<Task<int>> tasks = new List<Task<int>>(); 

    for (int i = 0; i < 10; i++) 
     tasks.Add(Task.Factory.StartNew((object state) => 
      { 
       int id = (int)state; 
       DoFirstStep(id); 
       _progressMessages.Add(new Tuple<int, int, string>(
        id, 1, "10.0%")); 
       DoSecondStep(id); 
       _progressMessages.Add(new Tuple<int, int, string>(
        id, 2, "50.0%")); 

       // ... 

       return 1; 
      }, 
      (object)i 
      )); 

    Task logger = Task.Factory.StartNew(() => 
     { 
      foreach (var m in _progressMessages.GetConsumingEnumerable()) 
       Console.WriteLine("Task {0}: Step {1}, progress {2}.", 
       m.Item1, m.Item2, m.Item3); 
     }); 


    List<Task> waitOn = new List<Task>(tasks.ToArray()); 
    waitOn.Add(logger); 
    Task.WaitAll(waitOn.ToArray()); 
    Console.ReadLine(); 
} 

private static void DoSecondStep(int id) 
{ 
    Console.WriteLine("{0}: First step", id); 
} 

private static void DoFirstStep(int id) 
{ 
    Console.WriteLine("{0}: Second step", id); 
} 

이 샘플에는 취소, 오류 처리 또는 작업 시간이 오래 걸릴 수 있다는 요구 사항이 표시되지 않습니다. 장기 실행 태스크는 스케줄러에 특별한 요구 사항을 배치합니다. 이것에 대한 더 많은 논의는 http://parallelpatterns.codeplex.com/에서 찾을 수 있으며, 책 초안을 다운로드하고 3 장을보십시오.

이것은 단순히 이와 같은 시나리오에서 작업 병렬 라이브러리를 사용하기위한 방법입니다. TPL은 이 아닐 수도 있습니다. 여기서는이 가장 좋습니다.

웹 서비스가 ASP에서 실행중인 경우.NET (또는 유사한 웹 응용 프로그램 서버) 당신은 또한 오히려 서비스 웹 요청보다 작업을 실행하는 스레드 풀에서 스레드를 사용의 가능성에 미치는 영향을 고려해야합니다

How does Task Parallel Library scale on a terminal server or in a web application?

+0

자세한 답변을 보내 주셔서 감사합니다. 나는 TPL이 최선의 접근법이 아닐 수도 있다는 것에 동의한다. 나는 그것을 사용할 수있는 기회를 얻기를 바라고 있었지만 다른 날을 기다려야 할 수도 있습니다 ... –

0

찾고있는 해결책에 Task API가 관련되어 있다고 생각하지 않습니다. 적어도 직접적으로는 아닙니다. 백분율 완료 개념을 지원하지 않으며 해당 레벨에서만 사용할 수있는 데이터이기 때문에 Task/ContinueWith 함수가 해당 논리에 참여해야합니다 (ContinueWith의 최종 호출 만 완료 비율을 알 수있는 위치에 있으며, 그리고 심지어 알고리즘 적으로 그렇게하는 것은 최선의 추측이 될 것입니다. 왜냐하면 하나의 작업이 다른 작업보다 오래 걸릴지를 확실히 알지 못하기 때문입니다. 작업 API를 활용하여 자신 만의 API를 만들 것을 제안합니다. 실제 작업을 수행하는

+0

그렇습니다. ContinueWith (...)를 사용하면 사실상 다른 모든 작업을 포함하는 큰 작업이 아니라 일련의 작업 체인이 있으므로 어떤 단일 작업도 앞서 무엇을 알 수 없습니까? 그것. 당신의 도움을 주셔서 감사합니다! –

관련 문제