Улучшение управления памятью в Net Core Windows -Service - PullRequest
0 голосов
/ 17 апреля 2020

Я хотел спросить о наилучшем подходе для использования консольного приложения, которое также можно использовать в качестве windows -сервиса в базовой среде net. Проблема не в том, что такое приложение, а в исполняемом коде. Я пытаюсь объяснить, в чем именно заключается моя проблема.

Если запущен сервис windows, инициируется for-l oop, который выполняет несколько действий,

  • . amazons AWS SQS
  • доступ через HTTP-запрос к csv-файлу => эти данные используются и частично сохраняются в db
  • при обращении к таблицам oracle db через EF ( вставить, обновить и удалить)

Пока все хорошо. Все работает так, как я хочу. Использование внедрения зависимостей (Scoped) для доступа в моем l oop к тем методам, которые я запрограммировал для выполнения всех действий.

Хитрость в том, что использование памяти этим приложением довольно ... не оптимально , Он делает то, что делает, но при загрузке и использовании данных CSV-файлов приложение использует слишком много памяти и не освобождается должным образом. Есть ли у вас какие-либо предложения или статьи базы знаний о том, как обращаться с таким сценарием ios (l oop в windows -сервисе)?

Я пытался высвободить все, что мог, например, очистку списков и настройку их значение равно нулю, отключено любое отслеживание в EF при запросе данных (также отключена дополнительная вставка / обновление средства отслеживания изменений) и используется «использование операторов» (/ удаление элементов).

Кроме того, я хотел бы добавить, что я использую последний SDK Amazon AWS (Core и SQS) и EF Core 2.2.6 с Oracle Provider.

Есть ли шанс, что у вас есть подсказка?

Если вам нужна дополнительная информация, просто скажите мне. Затем я предоставлю больше данных по мере необходимости.

С уважением


Относительно комментария чтения файла CSV

Чтение файла с URL.

        using (var response = await request.GetResponseAsync())
            {
                await using (var receiveStream = response.GetResponseStream())
                {
                    using (var readStream = new StreamReader(receiveStream, Encoding.UTF8))
                    {
                        var content = readStream.ReadToEnd();
                        result.Content = content.Split('\n').ToList();

                        result.IsSuccess = true;
                    }
                }
            }

и после прочтения я конвертирую его в целевой класс

public static async Task<List<Curve>> ReturnCurveData(List<string> content)
    {
        var checkVar = -1;
        var list = new List<Curve>();

        foreach (var entry in content)
        {
            if (string.IsNullOrEmpty(entry)) continue;

            var entrySplitted = entry.Split('|');
            if (entrySplitted.Length < 3) continue;
            else if(!int.TryParse(entrySplitted[0], out checkVar)) continue;

            var item = new Curve();
            item.Property1 = Convert.ToInt32(entrySplitted[0]);
            item.Property2 = (entrySplitted.Length ==3) ? DateTime.Now : Convert.ToDateTime(entrySplitted[1]);
            item.Property3 = (entrySplitted.Length ==3) ? Convert.ToDateTime(entrySplitted[1]) : Convert.ToDateTime(entrySplitted[2]);
            item.Value = (entrySplitted.Length ==3) ? Convert.ToDecimal(entrySplitted[2], new CultureInfo("en-US")): Convert.ToDecimal(entrySplitted[3], new CultureInfo("en-US"));

            list.Add(item);
        }

        return await Task.FromResult(list);
    }

Относительно определения контекста

var hostBuilder = new HostBuilder()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                ...
            })
            .ConfigureServices((hostContext, services) =>
            {
                services.AddScoped<Data.Queries.Database.Db>();
                services.AddScoped<Data.Queries.External.Aws>();
                services.AddScoped<Data.Queries.External.Web>();
                services.RegisterEfCoreOracle<DbContext>(AppDomain.CurrentDomain.BaseDirectory,
                    "cfg_db.json");
                services.AddScoped<IExecute, Execute>();
                services.AddHostedService<ExecuteHost>();
            })
            .ConfigureLogging((hostingContext, logging) =>
            {
                ...
            });

public static void RegisterEfCoreOracle<T>(this IServiceCollection services, string configurationDirectory, string configurationFile, ServiceLifetime lifetime = ServiceLifetime.Scoped) where T : DbContext
    {
        //Adding configuration file
        IConfiguration configuration = new ConfigurationBuilder()
            .SetBasePath(configurationDirectory)
            .AddJsonFile(configurationFile, optional: false)
            .Build();

        services.Configure<OracleConfiguration<T>>(configuration);

        var oraConfig = services.ReturnServiceProvider().GetService<IOptions<OracleConfiguration<T>>>();

        if (oraConfig.Value.Compatibility != null)
        {
            services.AddDbContext<T>(o => o
                .UseOracle(oraConfig.Value.ConnectionString(), b => b
                    .UseOracleSQLCompatibility(oraConfig.Value.Compatibility)), lifetime);
        }

        else
        {
            services.AddDbContext<T>(o => o
                .UseOracle(oraConfig.Value.ConnectionString()), lifetime);
        }
    }

1 Ответ

0 голосов
/ 17 апреля 2020

Ну, так как вы разместили свой код, мы можем довольно легко проанализировать проблему:

var content = readStream.ReadToEnd();

Как я уже говорил, никогда не читайте файл в памяти, обрабатывайте его построчно, например, используя StreamReader или StringReader, или любой из миллиона парсеров CSV в Nuget.

 result.Content = content.Split('\n').ToList();

Вы не только читаете весь файл в памяти, но и разбиваете его на значения (поэтому в дополнение ко всему содержимому файла , вы выделяете массив длины, равной количеству строк, и для каждой строки, выделяющей строки для каждого элемента, разделенного запятой, для общего количества строк * элементов строки) и в дополнение ко всем этим , выделяющим еще один список и копирование содержимого массива в него.

Редактировать: Вы разбиваете его на строки здесь и на значения во второй части. Мой анализ правильный, но проблема разбита на несколько строк.

Само собой разумеется, это в лучшем случае смешно. Прекратите использовать Split, не ToList без необходимости и не читайте все сразу. Вы пишете веб-сервер, теоретически все это можно сделать один раз для каждого обработанного запроса, что может легко go в десятках в зависимости от вашего процессора.

Я не буду go над второй частью, но это даже хуже. С первого взгляда я вижу еще больше списков и еще больше Split с. А строка return await Task.FromResult(list); показывает, что вы вообще не понимаете асин c функций. Не только то, что у вас есть, вовсе не asyn c, но если вы настаиваете на том, чтобы сделать его asyn c, просто возвращайте список напрямую, а не как ожидаемую задачу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...