c# - 在 Xamarin 中进行批量插入时启动阻塞 GC 显式
问题描述
我正在. Xamarin
_ bulk insert
_synchronization
rest api
所以我尝试了很多方法来避免它,但它们没有奏效。
使用单例连接,在创建连接时添加参数并在连接中使用using
关键字dispose
。
我有 9000 个寄存器,每次获取并分页大约 1000 个寄存器。
当它到达最后一个分页页面时,它停止并且控制台给出了这样的消息。
11-19 11:52:17.453 I/art (32524): Starting a blocking GC Explicit
11-19 11:52:17.463 I/art (32524): Explicit concurrent mark sweep GC freed 97(4KB) AllocSpace objects, 0(0B) LOS objects, 27% free, 10MB/14MB, paused 380us total 15.150ms
11-19 11:52:17.463 D/Mono (32524): GC_TAR_BRIDGE bridges 120 objects 126 opaque 9 colors 120 colors-bridged 120 colors-visible 120 xref 0 cache-hit 0 cache-semihit 0 cache-miss 0 setup 0.09ms tarjan 0.11ms scc-setup 0.16ms gather-xref 0.01ms xref-setup 0.00ms cleanup 0.04ms
11-19 11:52:17.463 D/Mono (32524): GC_BRIDGE: Complete, was running for 18.02ms
11-19 11:52:17.463 D/Mono (32524): GC_MAJOR: (LOS overflow) time 50.76ms, stw 60.27ms los size: 4096K in use: 1369K
11-19 11:52:17.463 D/Mono (32524): GC_MAJOR_SWEEP: major size: 8208K in use: 6622K
11-19 11:52:17.693 D/Mono (32524): GC_TAR_BRIDGE bridges 0 objects 0 opaque 0 colors 0 colors-bridged 0 colors-visible 120 xref 0 cache-hit 0 cache-semihit 0 cache-miss 0 setup 0.09ms tarjan 0.11ms scc-setup 0.16ms gather-xref 0.01ms xref-setup 0.00ms cleanup 0.00ms
11-19 11:52:17.693 D/Mono (32524): GC_BRIDGE: Complete, was running for 0.10ms
11-19 11:52:17.693 D/Mono (32524): GC_MINOR: (Nursery full) time 2.45ms, stw 3.05ms promoted 10K major size: 8240K in use: 6634K los size: 4096K in use: 1650K
11-19 11:52:17.933 D/Mono (32524): GC_TAR_BRIDGE bridges 0 objects 0 opaque 0 colors 0 colors-bridged 0 colors-visible 120 xref 0 cache-hit 0 cache-semihit 0 cache-miss 0 setup 0.09ms tarjan 0.11ms scc-setup 0.16ms gather-xref 0.01ms xref-setup 0.00ms cleanup 0.00ms
11-19 11:52:17.933 D/Mono (32524): GC_BRIDGE: Complete, was running for 0.28ms
11-19 11:52:17.933 D/Mono (32524): GC_MINOR: (Nursery full) time 2.42ms, stw 3.03ms promoted 2K major size: 8240K in use: 6636K los size: 4096K in use: 1916K
批量插入方法
public void BulkInsert(JArray array, string tableName = "")
{
try
{
if (string.IsNullOrEmpty(tableName))
{
Type typeParameterType = typeof(T);
tableName = typeParameterType.Name;
}
StringBuilder stringBuilder = new StringBuilder();
array.ToList().ForEach(register =>
{
stringBuilder.AppendLine(DataBaseUtil.GenerateInsertStatement(register, tableName));
});
SQLiteCommand command = new SQLiteCommand(ConnectionDataBase.Connection);
command.CommandText = stringBuilder.ToString();
command.ExecuteNonQuery();
}
catch (Exception e)
{
LogUtil.WriteLog(e);
}
public static string GenerateInsertStatement(JToken register, string tableName)
{
var data = JsonConvert.DeserializeObject<Dictionary<string, string>>(register.ToString());
string columns = string.Join(",", data.Keys.ToList());
string values = string.Join(",", data.Values.Select(v => string.Format(@"'{0}'", v.Trim())));
return string.Format("INSERT INTO {0} ({1}) VALUES ({2}); ", tableName, columns, values);
}
适用于这么多记录的方法
private async Task GenerateOrdensServico()
{
try
{
_logs.Add("ORDENS DE SERVIÇO");
double increment = ((1 - Progresso) / 2);
int records = await _ordemServicoRest.GetCount();
int limit = _sistemaParametroRepository.GetTamanhoPaginaSincMobile();
int pages = (records / limit);
for (int i = 0; i <= pages; i++)
{
JArray ordensServico = await _ordemServicoRest.GetAllInJsonFormatPaginated(DataBaseUtil.GetPagination(i, limit));
if (ordensServico == null)
{
_logs.Add("Não Contem O.S de Corte para importar!");
await App.Current.MainPage.DisplayAlert("Atenção", "Não tem O.S para importar!", "OK");
continue;
}
_ordemServicoRepository.BulkInsert(ordensServico);
AlterProgress(Progresso += ((Progresso * 100) + (increment / pages)));
}
}
catch (Exception e)
{
LogUtil.WriteLog(e);
}
}
我的 http 获取方法
protected async Task<Object> GetValue(string metodo = "", string parametros = "")
{
try
{
_urlBase = new Uri(GetStringConnectionParameters(metodo) + parametros);
using (HttpClient client = new HttpClient())
using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, _urlBase))
using (HttpResponseMessage response = await client.SendAsync(request))
{
Stream content = await response.Content.ReadAsStreamAsync();
if (response.IsSuccessStatusCode)
{
return DeserializeJsonFromStream<Object>(content);
}
}
}
catch (Exception e)
{
LogUtil.WriteLog(e);
}
return null;
}
以及调用我需要在数据库中插入的实体列表的方法
private async Task RegistrarDados()
{
try
{
_logs.Add("Realizando o Download: ");
AlterProgress(12.5);
await GenerateAtendimentoMotivosEncerramento();
AlterProgress(15);
await GenerateHidrometrosLocalInstalacao();
AlterProgress(17.5);
await GenerateHidrometrosProtecao();
AlterProgress(20);
await GenerateFuncionarios();
AlterProgress(25);
await GenerateGrupoFaturamento();
AlterProgress(30);
await GenerateLigacaoAguaSituacoes();
AlterProgress(40);
await GenerateLigacaoEsgotoSituacoes();
AlterProgress(45);
await GenerateServicosTipo();
AlterProgress(50);
await GenerateSistemParametros();
AlterProgress(55);
await GenerateOrdensServico();
AlterProgress(55);
await GenerateContas();
int contador = _ordemServicoRepository.Count<OrdemServico>();
AlterProgress(100);
_logs.Add("Sincronização encerrada com sucesso!");
await App.Current.MainPage.DisplayAlert("Atenção", "Foram importados " + contador + " Ordens de Serviços!", "OK");
PodeSincronizar = true;
}
catch (Exception e)
{
LogUtil.WriteLog(e);
}
}
这些方法GenerateSistemParametros(); GenerateOrdensServico(); GenerateContas();
需要按此顺序执行,因为它们具有依赖性。
编辑
我也先尝试了这种方法来保存
public void BulkInsert(JArray array, string tableName = "")
{
try
{
if (string.IsNullOrEmpty(tableName))
{
Type typeParameterType = typeof(T);
tableName = typeParameterType.Name;
}
using (SQLiteConnection connection = new SQLiteConnection(DataBaseUtil.GetDataBasePath()))
{
connection.BeginTransaction();
array.ToList().ForEach(register =>
{
string sql = DataBaseUtil.GenerateInsertStatement(register, tableName);
System.Diagnostics.Debug.WriteLine(sql);
var command = connection.CreateCommand(sql);
command.ExecuteNonQuery();
});
connection.Commit();
DataBaseUtil.CloseConnection(connection);
}
}
catch (Exception e)
{
LogUtil.WriteLog(e);
}
}
解决方案
关于使用的观察HttpClient
参考您使用的 HttpClient 错误,它正在破坏您的软件
private static Lazy<HttpClient> client = new Lazy<HttpClient>();
protected async Task<Object> GetValue(string metodo = "", string parametros = "") {
try {
_urlBase = new Uri(GetStringConnectionParameters(metodo) + parametros);
using (HttpResponseMessage response = await client.Value.GetAsync( _urlBase)) {
if (response.IsSuccessStatusCode) {
Stream content = await response.Content.ReadAsStreamAsync();
return DeserializeJsonFromStream<Object>(content);
}
}
} catch (Exception e) {
LogUtil.WriteLog(e);
}
return null;
}
推荐阅读
- micronaut - 我们如何使用 micronaut Kafka 从 Kafka 状态存储中检索数据?
- .net - F#类型注释问题
- docker - 重试连接服务器:已尝试 9 次;重试策略是 RetryUpToMaximumCountWithFixedSleep(maxRetries=10, sleepTime=1000 MILLISECONDS)
- c# - 如何在 Asp.Net Core MVC 中处理 JWT 令牌
- syntax-error - 为什么在这个非常简单的打印命令中有语法错误
- django - 迁移时为所有用户更新新字段
- google-analytics - 谷歌分析自定义数据
- javascript - 致命错误:使用任何“npm”命令时 JavaScript 堆内存不足
- git - 使用 CI/CD 将我的 git 存储库的每个子目录部署到不同的目标
- javascript - TypeError:无法读取未定义的属性“接口”