HttpClient многопоточный парсинг уникальных ссылок

Рейтинг: 0Ответов: 1Опубликовано: 08.05.2023

В продолжение предыдущего вопроса. Описываю более конкретно. Есть локальный сервер, который хранит файлы. Путь к каждому файлу уникален и по ссылке вида: localhost:8042/instances/UNIQUE_ID я получаю нужный мне JSON ответ. Мне нужно спарсить все файлы как можно быстрее, поэтому я создаю один экземпляр httpclient и делаю параллельные запросы. В результате на каждый такой запрос создается отдельный сокет и их количество в какой-то момент кончается. Вопрос - как подобное решить? Подход через семафор бесполезен, поскольку ссылки уникальны и я не подключаюсь по одному и тому же пути. MaxConnectionsPerServer, также, не подходит по той же самой причине. ConnectionLifeTime попросту не работает, ввиду судя по всему системной нижней границы. Каким образом я могу без костылей в виде реестра снизить время жизни соединения или переиспользовать уже открытое соединение?

Основной код:

ParsingInstance Instances = new();
ParsingSeries Series = new();
ParsingPatients Patients = new();
ParsingStudies Studies = new();
List<string> exceptions = new();
using HttpClient client = new(new SocketsHttpHandler());

var tasks = new List<Task>
{
    Instances.DataGetter(Datas.GetValueOrDefault("Instances"), client, exceptions2),
    Series.DataGetter(Datas.GetValueOrDefault("Series"), client, exceptions),
    Patients.DataGetter(Datas.GetValueOrDefault("Patients"), client, exceptions),
    Studies.DataGetter(Datas.GetValueOrDefault("Studies"), client, exceptions)
};
await Task.WhenAll(tasks);

Класс ParsingPatients (остальные наследуются от него)

 public class ParsingPatients
    {
        public string PatientPath { get; set; }
        public string ID { get; set; }

        public MainDicomTags? mainDicomTags { get; set; }
        public class MainDicomTags
        {
            public string? PatientName { get; set; }
            public string? PatientSex { get; set; }
            public string? PatientBirthDate { get; set; }
            public string? PatientID { get; set; }
        }

        public async Task DataGetter(string url, HttpClient Client, List<string> exceptions)
        {
            var DataIDs = await Client.GetFromJsonAsync<List<string>>(url);
            Task[] DataTasks = new Task[DataIDs.Count];
            for (var i = 0; i < DataTasks.Length; i++)
                DataTasks[i] = GetData(i, url, Client, DataIDs, exceptions);
            await Task.WhenAll(DataTasks);
            Console.WriteLine($"Получение данных из: {url} окончено");
        }
        public virtual async Task GetData(int index, string url, HttpClient Client, List<string> obj, List<string> exceptions)
        {
            try
            {
                ParsingPatients? Ppatient = new();
                Ppatient =  await Client.GetFromJsonAsync<ParsingPatients>($"{url}/{obj[index]}");
                Ppatient.PatientPath = $"{url}/{obj[index]}";
                Ppatient = ToString(ref Ppatient);
                Patients patient = new();
                patient = await ConvertData(Ppatient, patient);
                await SQLiteDbContext.AddDataToDb(patient);

            }
            catch (Exception ex) { exceptions.Add($"Ошибка:{ex.InnerException.Message}\nошибка в {url}/{obj[index]}"); }
        }

Ответы

▲ 1Принят

Окей, дубль 2.

Попробуйте ограничить количество одновременно работающих запросов. Это должно смягчить или прекратить эффект истощения сокетов.

private static readonly SemaphoreSlim semaphore = new(Environment.ProcessorCount * 2);
private static readonly HttpClient client = new(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.All })
{
    DefaultRequestVersion = HttpVersion.Version20
};
public async Task<T> GetJsonAsync<T>(string url)
{
    await semaphore.WaitAsync();
    try
    {
        return await client.GetFromJsonAsync<T>(url);
    }
    finally
    {
        semaphore.Release();
    }
}

Ну и вызывать вот так

var DataIDs = await GetJsonAsync<List<string>>(url);

patient = await GetJsonAsync<Patients>($"{url}/{obj[index]}");