2015-05-11 5 views
2

Я создал класс для обработки нескольких HTTP-запросов GET. Это выглядит примерно так:Оптимизация запросов asyncronus HttpClient

public partial class MyHttpClass : IDisposable 
{ 
    private HttpClient theClient; 
    private string ApiBaseUrl = "https://example.com/"; 

    public MyHttpClass() 
    { 

     this.theClient = new HttpClient(); 
     this.theClient.BaseAddress = new Uri(ApiBaseUrl); 
     this.theClient.DefaultRequestHeaders.Accept.Clear(); 
     this.theClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); 
    } 

    public async Task<JObject> GetAsync(string reqUrl) 
    { 

     var returnObj = new JObject(); 
     var response = await this.theClient.GetAsync(reqUrl); 

     if (response.IsSuccessStatusCode) 
     { 
      returnObj = await response.Content.ReadAsAsync<JObject>(); 
      Console.WriteLine("GET successful"); 

     } 
     else 
     { 
      Console.WriteLine("GET failed"); 
     } 

     return returnObj; 
    } 
    public void Dispose() 
    { 
     theClient.Dispose(); 
    } 
} 

Я тогда несколько очередей requets, используя цикл по Task.Run(), а затем после Task.WaitAll() в виде:

public async Task Start() 
{ 
    foreach(var item in list) 
    { 
     taskList.Add(Task.Run(() => this.GetThing(item))); 
    } 
    Task.WaitAll(taskList.ToArray()); 
} 

public async Task GetThing(string url) 
{ 
    var response = await this.theClient.GetAsync(url); 

    // some code to process and save response 

} 

Это определенно работает быстрее, чем синхронизация, но это не так быстро, как я ожидал. Основываясь на других советах, я думаю, что местный threadpool замедляет меня. MSDN предлагает мне указать его как долговременную задачу, но я не вижу способа сделать это, назвав это так.

Прямо сейчас у меня нет ограниченных потоков, я просто делаю партии и проверяю скорость, чтобы найти правильный подход.

Может кто-нибудь предложить некоторые области для меня, чтобы посмотреть, чтобы увеличить скорость?

ответ

4

Итак, после того как вы установите DefaultConnectionLimit в хороший большой номер, или просто ConnectionLimit из Servicepoint, который управляет соединениями с хостом вы ударяя:

ServicePointManager 
    .FindServicePoint(new Uri("https://example.com/")) 
    .ConnectionLimit = 1000; 

единственный подозреваемый бит кода где вы начинаете все ...

public async Task Start() 
{ 
    foreach(var item in list) 
    { 
     taskList.Add(Task.Run(() => this.GetThing(item))); 
    } 
    Task.WaitAll(taskList.ToArray()); 
} 

Это может быть сведено к

var tasks = list.Select(this.GetThing); 

для создания задачи (ваши методы возврата асинхронных горячие (бег) задачи ... Не надо двойной оберткой с Task.Run)

Тогда, скорее, что блокирование во время ожидания их завершения, ждать асинхронно вместо:

await Task.WhenAll(tasks); 
+0

Настройка менеджера Servicepoint и изменения в WhenAll() дал прирост производительности. Завтра сделаем несколько больших партий, чтобы увидеть, сколько. Если я развожу такие задачи, как вы предлагали, он загружает все запросы в том же потоке. Мне нужно делать большие партии, чтобы справиться, если это лучше или нет. На нескольких прогонах, подобных задачам, которые объявляют одно и то же имя потока, я получил некоторые сбои GET, и он зависал, но он, возможно, был несвязан (чтобы было ясно, что они запускаются в то же время, но в одном и том же идентификаторе потока, тогда как другим способом является несколько потоков Используемые идентификаторы). – Guerrilla

+0

@guerrilla Да, первая часть асинхронного метода (прежде чем вы нажмете первый вызов) работает синхронно. Это нормально. Вам не нужно кодировать это. – spender

0

Возможно, вы нанесли некоторые накладные расходы при создании нескольких экземпляров HttpClient против использования экземпляра static. Ваша реализация не будет масштабироваться. Рекомендуется использовать общий HttpClient.

Смотрите мой ответ, почему - What is the overhead of creating a new HttpClient per call in a WebAPI client?

Смежные вопросы