关于C# WinForm开发海量数据入库解决方案及使用进度条ProgressBar的经验之谈

10 篇文章 2 订阅
3 篇文章 0 订阅

1.问题

最近在做一个由ArcGIS数据格式导入到PostgreslSQL的小工具,数据量比较大(千万级别,见下图),起初为了给使用者一个“比较好”的使用体验,耍了点"小聪明",在导入的界面上增加了两个ProgressBar,一个用于实时显示表的进度,另一个用于实时显示表记录的进度。开发好真正投入使用时,引发了一系列的不满(导入慢、出现未响应假死等等)。

2.解决办法

2.1忽滥用ProgressBar

问题如上述,有一个PorgressBar是用于实时显示表记录进度的,排查了很久才想明白,行记录有多少UI就更新多少次,所以一定程度上影响了入库的效率,好,首先把行记录的进度条给屏蔽,F5(表808个,记录33万),时间缩短了3/4,天啊....

        解决办法:

        (1)、忽滥用ProgressBar;

        (2)、适当增加更新值的间隔

        

2.2批量提交

如100条提交一次,但这样不利用审计。

 if (currentCount % 100 == 0 || currentCount== featureCount)
 {
    AppConst.postgreHelper.ExecuteNonQuery(connString, CommandType.Text, commitSQL);
    commitSQL = "";
 }
 //AppConst.postgreHelper.ExecuteNonQuery(connString, CommandType.Text, sql);

2.3采用多线程

定义入库任务类:

    public class DataImportTask
    {
        //更新主线程ProgressBar的委托
        public delegate void UpdateProgressBar(int step);
        public UpdateProgressBar UpdateProgressBarDelegate;

        //完成入库任务时通知主线程的委托
        public delegate void DataImportFinishTask();
        public DataImportFinishTask FinishCallBack;

        public void DoWork(object obj)
        {
            var options = (ImportOptions)obj;
            var count = options.CurrentCount;
            var interval = options.Interval;

            for (int i = 0; i < count; i++)
            {
                //根据间隔更新主线程ProgressBar进度
                if (i % interval == 0)
                    UpdateProgressBarDelegate(interval);
            }

            //任务完成时通知主线程作出相应的处理
            FinishCallBack();
        }
    }

定义需要传的参数


    public class ImportOptions
    {
        /// <summary>
        /// 进度条更新间隔
        /// </summary>
        public int Interval { get; set; }

        /// <summary>
        /// 当前线程入库数量
        /// </summary>
        public int CurrentCount { get; set; }
    }

执行多线程

public partial class FrmMain : Form
    {
        delegate void AsynUpdateProgressBar(int step);

        public FrmMain()
        {
            InitializeComponent();
        }

        private void Button1_Click(object sender, EventArgs e)
        {
            int total = 1000000000;

            int taskCount = Convert.ToInt32(textBox1.Text.ToString());
            int count = total / taskCount;

            var options = new ImportOptions {
                CurrentCount = count,
                Interval=100000
            };

            progressBarX1.Maximum = total;
            progressBarX1.Minimum = 0;
            progressBarX1.Value = 0;

            for (int i = 0; i < taskCount; i++)
            {
                DataImportTask dataTask = new DataImportTask();
                dataTask.UpdateProgressBarDelegate += UpdataProgressBarStatus;
                dataTask.FinishCallBack += FinishCallBack;

                Thread t = new Thread(new ParameterizedThreadStart(dataTask.DoWork));
                t.IsBackground = true;
                t.Start(options);
            }
        }

        //更新进度条
        private void UpdataProgressBarStatus(int step)
        {
            if (InvokeRequired)
            {
                this.Invoke(new AsynUpdateProgressBar(delegate (int s)
                {
                    this.progressBarX1.Value += s;
                }), step);
            }
            else
            {
                this.progressBarX1.Value += step;
            }
        }

        //完成导入任务
        private void FinishCallBack()
        {
            MessageBox.Show("任务完成...");
        }
    }

以1000000000为例,最终如下图所示:

 

  • 0
    点赞
  • 1
    收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:创作都市 设计师:CSDN官方博客 返回首页
评论 1

打赏作者

大龄Giser

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值