2009-04-30 4 views
0

저는 현재 사이트를 긁어서 XML 사이트 맵을 만드는 사이트 맵 생성기를 작성하고 있습니다. 대부분의 대기는 uri에 대한 요청에 소요되므로 스레딩을 사용하고 있습니다. 특히 ThreadPool 객체에서 빌드하는 것이 좋습니다.C#에서 알 수없는 양의 스레드 스레딩

주 스레드가 알려지지 않은 양의 스레드를 완료 할 때까지 대기하도록하기 위해 다음 설치를 구현했습니다. 나는 이것이 좋은 해결책이라고 생각하지 않는다. 어떤 스레딩 전문가가이 솔루션에 어떤 문제가 있는지 조언 해 주거나 그것을 구현하는 더 좋은 방법을 제안 할 수 있습니까?

EventWaitHandle 여기

EventResetMode.ManualReset

설정된다

// Request first page (based on host) 
Uri root = new Uri(context.Request.Url.GetLeftPart(UriPartial.Authority)); 

// Begin threaded crawling of the Uri 
ThreadPool.QueueUserWorkItem(_waitCallback, root); 
Thread.Sleep(5000); // TEMP SOLUTION: Sleep for 5 seconds 
_eventWaitHandle.WaitOne(); 

// Server the Xml Sitemap 
context.Response.ContentType = "text/xml"; 
context.Response.Write(GetXml().OuterXml); 

어떤 아이디어가 많은 이해하는 메인 쓰레드 방법 :

에게 인 스레드있어서 여기

protected void CrawlUri(object o) 
    { 

     try 
     { 
      Interlocked.Increment(ref _threadCount); 
      Uri uri = (Uri)o; 

      foreach (Match match in _regex.Matches(GetWebResponse(uri))) 
      { 
       Uri newUri = new Uri(uri, match.Value); 

       if (!_uriCollection.Contains(newUri)) 
       { 
        _uriCollection.Add(newUri); 
        ThreadPool.QueueUserWorkItem(_waitCallback, newUri); 
       } 
      } 
     } 
     catch 
     { 
      // Handle exceptions 
     } 
     finally 
     { 
      Interlocked.Decrement(ref _threadCount); 
     } 

     // If there are no more threads running then signal the waithandle 
     if (_threadCount == 0) 
      _eventWaitHandle.Set(); 
    } 

답변

1

먼저, 설정을 시작한 ManualResetEvent를 만들 수 있으므로 기다리기 전에 잠자기 할 필요가 없습니다. 두 번째로는 Uri 컬렉션에서 스레드 동기화를 수행해야합니다. 하나의 두 스레드가 "이 Uri가 아직 존재하지 않습니다"체크를 통과하고 중복을 추가하는 경쟁 조건을 얻을 수 있습니다. 또 다른 경쟁 조건은 두 개의 스레드가 if (_threadCount == 0) 검사를 통과 할 수 있고 둘 다 이벤트를 설정할 수 있다는 것입니다.

마지막으로 비동기식 BeginGetRequest를 사용하면 훨씬 더 효율적으로 작업 할 수 있습니다. 귀하의 솔루션은 현재 스레드가 모든 요청을 기다리게합니다. 비동기 메서드와 콜백을 사용하면 프로그램에서 사용하는 메모리가 적어 (스레드 당 1MB) 스레드의 컨텍스트 전환을 거의 수행 할 필요가 없습니다.

다음은 내가 말하는 것에 대한 예시입니다. 호기심에서 나는 그것을 (깊이 제한으로) 시험해 보았고 효과가 있었다.

+0

매우 흥미로 웠습니다. 고맙습니다. 주말 내내 시험 사용해 볼 수있는 기회를 갖기를 바랍니다.나는 비동기 요청에 대해 잊어 버렸다고 믿을 수 없다. o – WDuffy

0

이런 종류의 논리를 할 때 나는 일반적으로 각 비동기 작업과이를 실행하는 데 필요한 데이터를 나타내는 개체를 만듭니다. 일반적으로이 개체를 수행 할 작업 모음에 추가합니다. 스레드 풀은 이러한 작업을 예약하고, 작업 완료시 컬렉션 자체에서 신호를 보낼 수 있도록 "완료"컬렉션에서 개체 자체를 제거하도록합니다.

"완료"컬렉션이 비어있을 때 작업이 완료되었습니다. 주 스레드는 아마도 완료된 각 작업에 의해 한 번 깨어 났을 것입니다.

0

Task Parallel Library의 CTP를 살펴보면이 방법이 더 간단 할 것입니다. 수행중인 작업은 "작업", 청크 또는 작업 단위로 나눌 수 있으며 작업을 제공하면 TPL이이를 병렬 처리 할 수 ​​있습니다. 내부적으로 쓰레드 풀을 사용하지만, 사용하기 쉽고 모든 작업이 끝날 때까지 기다리는 것과 같은 많은 옵션이 있습니다. 가능성이 설명되어 있고 재귀 적으로 트리를 순회하는 데모가 표시되는 곳인 this Channel9 비디오를 확인하십시오. 이는 귀하의 문제에 매우 적합합니다.

아직까지는 미리보기이므로 .NET 4.0 이전에는 출시되지 않으므로 보증이 제공되지 않으며 제공된 System.Threading.dll (설치 폴더에 있음)을 수동으로 포함시켜야합니다. 귀하의 프로젝트와 나는 그것이 당신에게 옵션인지 여부를 모른다.

+0

줄리안은 정말 재미있어 보인다. 나는이 구현에서 그것을 사용할 수 없을 것이지만 나는 그것을 조사 할 것이다. 감사 :) – WDuffy

관련 문제