Окей, Dokey, так что я решил, что прыгну в ASP.Net Core для сервера отчетов. Теперь цель этого состояла в том, чтобы кэшировать и агрегировать отчеты, которые затем можно было бы распространять среди клиентов.
Поэтому, прежде чем я настрою все, чтобы начать выполнять вызовы API для опроса данных, я полагал, что построю строительные леса с использованием CSV,и потому, что это в основном формат данных, в котором они уже находятся.
В природе модели MVC я построил простую модель
public class MyModel {
public string ComputerName { get; set; }
public string IPAddress { get; set; }
public string SMART_Data { get; Set; }
}
Теперь мой простой dbcontext
public class MyContext: DbContext {
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Filename=bigfix.db");
}
public DbSet<MyModel> MyDatabase { get; set; }
}
My Setup.cs
public class Startup
{
public IConfiguration Configuration { get; }
public IHostingEnvironment Environment;
public Startup(IConfiguration configuration, IHostingEnvironment env)
{
Configuration = configuration;
Environment = env;
using(var context = new MyContext())
{
context.Database.EnsureCreated();
}
}
public void ConfigureServices(IServiceCollection services)
{
services.AddEntityFrameworkSqlite().AddDbContext<MyContext>();
services.AddHostedService<MyService>();
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseMvc();
}
}
My Service, с очень дерзким чтением CSV
public class MyService : IHostedService, IDisposable
{
private Timer timer;
private ILogger<MyService> logger;
private readonly IServiceScopeFactory scopeFactory;
public MyService(ILogger<MyService> logger, IServiceScopeFactory scopeFactory)
{
this.scopeFactory = scopeFactory;
this.logger = logger;
}
public Task StartAsync(CancellationToken stoppingToken)
{
timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(10));
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken stoppingToken)
{
timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void readCsv(StreamReader reader,Action<List<string>> processLine)
{
string line;
List<string> cells = new List<string>();
StringBuilder sb = new StringBuilder();
int lineCount = 0;
while ((line = reader.ReadLine()) != null)
{
cells.Clear();
bool escaped = false;
char c;
int cIndex = -1;
lineCount++;
for (int index = 0; index < line.Length; index++)
{
cIndex++;
c = line[index];
if (escaped)
{
if (c == '"')
{
if (index + 1 < line.Length && line[index + 1] == '"')
{
index++;
}
else
{
escaped = false;
}
}
if (escaped)
{
sb.Append(c);
}
}
else
{
switch (c)
{
case ',':
cells.Add(sb.ToString());
sb.Clear();
cIndex = -1;
break;
case '"':
if (cIndex == 0)
{
escaped = true;
break;
}
goto default;
default:
sb.Append(c);
break;
}
}
}
cells.Add(sb.ToString());
sb.Clear();
processLine(cells);
}
}
private async void DoWork(object state)
{
using (IServiceScope scope = scopeFactory.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<>();
context.ChangeTracker.AutoDetectChangesEnabled = false;
await context.Database.ExecuteSqlCommandAsync("DELETE FROM MyDatabase");
await context.SaveChangesAsync();
string path = "MyReport.csv";
using (StreamReader reader = new StreamReader(path))
{
readCsv(reader, async (List<string> cells) =>
{
Models.BigFix r = new Models.BigFix();
r.ComputerName = cells[0];
r.IPAddress = cells[1];
r.SMARTIDData = cells[2];
await context.MyDatabase.AddAsync(r);
});
}
await context.SaveChangesAsync();
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect(2, GCCollectionMode.Default, true, true);
}
}
public void Dispose()
{
timer?.Dispose();
}
}
Теперь, чтобы заполнить некоторые пробелы, причина, по которой я добавил читатель janky CSV:потому что, когда я использовал CSVHelper Просто прочитал использование CSV с шипами в диапазоне 1GB, и, насколько я могу судить, это из-за LOH.
Итак, я добавил кучу вещей GC, но это неСделать разницу. Затем я добавил построчное чтение CSV и ОГРОМНОЕ использование оперативной памяти прекратилось, но в тот момент, когда я начал вставлять данные в базу данных, они возвращались.
CSV, который я читаю, составляет около 26 тысяч строк. и 5 МБ в размере. Причиной повторной обработки CSV каждые 5 секунд было подтверждение утечки.
Я не знаю, что делать, удаление или повторное добавление данных объемом 5 МБ в SQLite приводит к тому, что использование оперативной памяти возрастает до1GB. Дайте мне знать, что вы думаете.