2014-08-30 3 views
3

나는 앱 목록을 통해 반복하는 프로그램을 가지고 있습니다.여러 http 요청 - 응답으로 작업

Apps 
-------- 
App1 
App2 
App3 

이제 각각에 대해 각 응용 프로그램의 빌드 목록을 XML로 가져 오기 위해 http 요청을합니다.

그래서 요청 같은

http://example.com/getapplist.do?appid=App1 

같은 나에게 응답을 제공
<appid name="App1"> 
    <buildid BldName="Bld3" Status="Not Ready"></buildid> 
    <buildid BldName="Bld2" Status="Ready"></buildid> 
    <buildid BldName="Bld1" Status="Ready"></buildid> 
</appid> 

가 지금은 상태 "준비"으로 최고 빌드 번호를 가져온 다음 다른 웹을 예 : 전화 번호 :

http://example.com/getapplist.do?appid=App1&bldid=Bld2 

이렇게하면 다음과 같은 응답이 표시됩니다.

<buildinfo appid="App1" buildid="Bld2" value="someinfo"></build> 

이러한 정보는 내부 데이터 테이블에 제공됩니다. 그러나 이제는 2000 개의 appids가 있고 각 id마다 2 개의 웹 요청이 있기 때문에이 프로그램을 완료하는 데 오랜 시간이 걸립니다 (3 시간). BackgroundWorker을 지정하여 here으로이 문제를 정렬 해 보았습니다. http 응답의 모든 정보를 단일 XML로 조합 한 다음 추가 처리를 위해 해당 XML을 사용한다고 생각했습니다. 이

파일이

if (!backgroundWorker1.IsBusy) 
{ 
    for(int i = 0; i < appList.Count; i++) 
    { 
     BackgroundWorker bgw = new BackgroundWorker(); 
     bgw.WorkerReportsProgress = true; 
     bgw.WorkerSupportsCancellation = true;      
     bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);     
     bgw.ProgressChanged += new ProgressChangedEventHandler(bgw_ProgressChanged); 
     bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted); 
     //Start The Worker 
     bgw.RunWorkerAsync(); 
    } 
} 

,

그래서 내 코드의 모습을 다른 프로세스에서 사용되는 오류를 던졌습니다 그리고 DoWork 기능은 태그 값을 선택합니다 및 XML에 넣는다 .

모든 백그라운드 작업자의 모든 http 응답에서 app-buildinfo 세부 정보를 공통 파일로 가져올 수있는 가장 좋은 방법은 무엇입니까?

+1

이 대신 한 BackgroundWorker에에서 webapi 비동기 전화 ... 그리고 잠금 이벤트 화재를 완료하고 XML 파일에 기록하여 WebRequest 비동기 중 하나를 사용하여 ... 좋지 않아 2000 backgroundworkers을 ... 생성합니다. – rene

+0

'DoWork' 메소드 코드를 추가해 주시겠습니까? –

+0

@rene 그래서 설정해야 할 한계는 무엇입니까? 또한, 5 명의 백그라운드 작업자라는 한계를 설정하면 모든 2K URL이 처리 될 때까지 스레드가 병렬로 실행된다는 의미입니까? – mhn

답변

4

HTTP 요청은 본질적으로 IO 바인딩 및 비동기이므로 필요한 작업을 수행하기 위해 백그라운드 작업자를 사용할 이유가 없습니다.

당신은 Microsoft.Bcl.AsyncHttpClient를 통해 .NET 4에서 호환 async-await을 활용할 수 있습니다 :

private async Task ProcessAppsAsync(List<string> appList) 
{ 
    var httpClient = new HttpClient(); 

    // This will execute your IO requests concurrently, 
    // no need for extra threads. 
    var appListTasks = appList.Select(app => httpClient.GetAsync(app.Url)).ToList(); 

    // Wait asynchronously for all of them to finish 
    await Task.WhenAll(appListTasks); 

    // process each Task.Result and aggregate them to an xml 
    using (var streamWriter = new StreamWriter(@"PathToFile") 
    { 
     foreach (var appList in appListTasks) 
     { 
      await streamWriter.WriteAsync(appList.Result); 
     } 
    } 
} 

이 방법, 당신은 동시에 모든 요청을 처리하고 그들이 완료 한 후 그들 모두의 결과를 처리합니다.

+0

@rene OP는 'Task.WhenAll' 다음에 필요한 경우 동 기적으로 쓸 수 있습니다.하지만 그 이유는 없습니다. –

+1

이 접근법을 시도해보고 결과를 업데이트 할 것입니다. – mhn

+0

@mhn 필요하다면'StreamWriter'를 사용하여 파일에 비동기 적으로 코드를 작성했습니다. –

0

이 솔루션은 WebClient 클래스에서 비동기 방법을 사용하여 파일에 대한 결과의 기록을 직렬화 상기 Interlocked 클래스와 감소합니다 카운터와 일반 lock를 사용하여 닷넷 2.0 이상 작동합니다.

var writer = XmlWriter.Create(
    new FileStream("api.xml", 
        FileMode.Create)); 
writer.WriteStartElement("apps"); // root element in the xml 
// lock for one write 
object writeLock = new object(); 
// this many calls    
int counter = appList.Count; 

foreach (var app in appList) 
{ 
    var wc = new WebClient(); 

    var url = String.Format(
     "http://example.com/getapplist.do?appid={0}&bldid=Bld2", 
     app); 
    wc.DownloadDataCompleted += (o, args) => 
     { 
      try 
      { 
       var xd = new XmlDocument(); 
       xd.LoadXml(Encoding.UTF8.GetString(args.Result)); 
       lock (writeLock) 
       { 
        xd.WriteContentTo(writer); 
       } 
      } 
      finally 
      { 
       // count down our counter in a thread safe manner 
       if (Interlocked.Decrement(ref counter) == 0) 
       { 
        // this was the last one, close nicely 
        writer.WriteEndElement(); 
        writer.Close(); 
        ((IDisposable) writer).Dispose(); 
       } 
      } 
     }; 
    wc.DownloadDataAsync(
     new Uri(url)); 
} 
+0

결과를 집계하고 한 번 쓰는 대신 파일에 너무 많은 동기 쓰기를 작성하여 잠금 경합을 전혀 사용하지 않는 이점을 실제로 볼 수 있습니까? –

+0

' 이 경우 확실하지 않지만 결과가 충분히 크면 문제가 될 수 있습니다. 또는 오류가 발생하여 다시 실행하는 데 비용이 많이 든다면 중간 결과가 나타납니다 (그러나 재시작 논리가 필요합니다). 많은 네트워크 연결을 열어 둘 가능성에 더 많은 관심이 있습니다. – rene

+0

그는 필요에 따라 요청을 항상 조절할 수 있으며, 'Task.W를 사용하여 끝내면 처리 할 수도 있습니다. 암탉. –

관련 문제