首页 > 解决方案 > 在 Xamarin 中进行批量插入时启动阻塞 GC 显式

问题描述

我正在. Xamarin_ bulk insert_synchronizationrest 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);
    }
}

标签: c#sqlitexamarin

解决方案


关于使用的观察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;
}

推荐阅读