2016-05-18 5 views
0

Ich muss eine Reihe von Aufrufen an einen einzelnen Webdienst für verschiedene Zeiträume tätigen und eine verkettete Ergebnismenge generieren. Ich möchte die Anrufe parallel machen, um den Prozess zu beschleunigen, obwohl ich in diesem Bereich wenig Erfahrung habe.Code läuft parallel in LinqPad, aber nicht in der Konsolen-App ... warum?

Ich habe verschiedene Techniken ausprobiert, aber basierend auf der Ausführungszeit laufen meine Codeaufrufe weiterhin in der Reihenfolge, wenn ich sie in einer Visul Studio Konsolenanwendung starte. Damit meine ich, wenn ein Anruf für einen einmonatigen Datumsbereich 15 Sekunden dauert, dann dauern drei der einmonatigen Anrufe, die angeblich parallel laufen, 45 Sekunden.

Aber hier ist der Teil, der mich wirklich überraschte: Ich begann den genau gleichen Code in LinqPad für das Debugging zu laufen. Und siehe, in LinqPad läuft derselbe Code parallel! Für 3 Monate zu telefonieren dauert ca. 15 Sekunden!

Jetzt kratze ich meinen Kopf, wie das sein könnte. Ich habe versucht, die LinqPad-Version in ein neues Conole-Projekt zu kopieren (um zu überprüfen, dass in beiden Versionen wirklich alles gleich ist), aber das Verhalten ändert sich nicht.

Ich würde mich über Vorschläge freuen. Ich bin nicht sicher, welcher Code für die Frage relevant ist, aber ich habe eine etwas vereinfachte Version der Web-Service-calling-Klasse unten enthalten:

class Importer 
{ 
    public List<FuncDetails> GetAllData(DateRange[] intervals) 
    { 
     Task<List<PropFuncsType>>[] tasks = intervals 
      .ToList() 
      .Select(interval => GetDataForIntervalAsync(interval.StartDate, interval.EndDate)) 
      .ToArray(); 

     var result = new List<ResultDataTable>(); 
     Task.Factory.ContinueWhenAll(tasks, results => { foreach (var output in results) { result.AddRange(output.Result); } }) 
     .Wait(); 

     return result.SelectMany(x => x.ResultDataRow).ToList(); 

    } 

    async static private Task<List<ResultDataTable>> GetDataForIntervalAsync(DateTime startDate, DateTime endDate) 
    { 
     var service = new ServiceClient(); 

     var result = await service.getDataAsync(new ServiceRequest() 
      { 
       startDate = string.Format("{0:yyyy-MM-dd}", startDate), 
       endDate = string.Format("{0:yyyy-MM-dd}", endDate) 
      } 
     ); 

     return result.ServiceResponse.ToList(); 
    } 
} 
+0

Haben Sie "ServicePointManager.DefaultConnectionLimit" überprüft? –

+0

Das war's! 'ServicePointManager.DefaultConnectionLimit' ist effektiv ein globaler Eintrag und der LinqPad-Host muss einen hohen Wert außerhalb meines Codes gesetzt haben. Ich habe mir zwei Tage lang den Kopf darüber geschlagen. Bitte machen Sie Ihren Kommentar zu einer Antwort, damit ich Ihnen einen angemessenen Kredit geben kann! –

Antwort

2

Versuchen ServicePointManager.DefaultConnectionLimit zu int.MaxValue eingestellt wird, wenn die Konsole App startet. Dies ist eine häufige, aber subtile Ursache der HTTP-Drosselung in .NET.

(Vermutlich LINQPad tut schon etwas Ähnliches).

+1

Den Wert von der Standardeinstellung (2) zu erhöhen, war genau die Antwort, obwohl ich anfänglich fand, dass es auf einen Wert weit über 24 (in meinem Fall) versehentlich zu einem Denial-of-Service-Angriff auf meinen eigenen Web-Service-Provider führte. :-) Mit großer Macht kommt große Verantwortung, und ich denke, dass diese Einschränkung wahrscheinlich besser in meinem Telefoncode verwaltet wird. Prost. –

Verwandte Themen