XDocument异步转DataTable实现多XML文件导入提速方案咨询
可行实现方案:管道化异步处理(加载/处理阶段重叠)
利用生产者-消费者模式把XML加载和DataTable写入拆成两个独立流程:XML加载作为生产者可以多线程并行跑(占2/3耗时的部分充分利用CPU/IO资源),DataTable写入作为消费者单线程按序处理(规避DataTable线程安全问题),刚好可以做到处理上一个已加载XML的同时,后台加载下一批XML。
推荐用.NET内置的Channel实现轻量级异步队列,代码示例如下:
private async void openXMLs() { OpenFileDialog openFileDialog1 = new OpenFileDialog { Title = "Browse XML files", CheckFileExists = true, CheckPathExists = true, DefaultExt = "xml", Filter = @"XML files (*.xml)|*.xml", FilterIndex = 2, RestoreDirectory = true, ReadOnlyChecked = true, ShowReadOnly = true, Multiselect = true }; if (openFileDialog1.ShowDialog() != DialogResult.OK) return; var files = openFileDialog1.FileNames; // 初始化Channel,缓存最多3个已加载的XDocument,避免内存占用过高 var channel = Channel.CreateBounded<XDocument>(3); // 控制XML加载的并发数,建议设为CPU核心数的1.5~2倍,兼顾IO和CPU开销 var semaphore = new SemaphoreSlim(Environment.ProcessorCount * 2); // 启动生产者任务:后台加载所有XML var producer = Task.Run(async () => { try { foreach (var file in files) { await semaphore.WaitAsync(); // 后台异步加载XML,不占用UI线程 var xdoc = await Task.Run(() => XDocument.Load(file)); await channel.Writer.WriteAsync(xdoc); semaphore.Release(); } } finally { channel.Writer.Complete(); } }); // 消费者任务:单线程写入DataTable,保证线程安全 var consumer = Task.Run(async () => { // 加载前关闭DataTable的行变更通知,大幅提升写入速度 _dt.BeginLoadData(); try { // 逐个读取已加载好的XDocument写入DataTable await foreach (var xdoc in channel.Reader.ReadAllAsync()) { loadData(xdoc); } } finally { _dt.EndLoadData(); } }); // 等待两个任务全部完成 await Task.WhenAll(producer, consumer); // 最后更新UltraGrid,操作要切回UI线程 ultraGrid1.DataSource = _dt; } // loadData方法可以保留,也可以做下方的优化 private void loadData(XDocument xdoc) { var rows = xdoc.Descendants("root") .Select(c => new object[] { c.Element("ID")?.Value, c.Element("firstname")?.Value, c.Element("lastname")?.Value, c.Element("state")?.Value }).ToArray(); // 批量添加行,比循环逐行Add快30%以上 foreach (var row in rows) { _dt.Rows.Add(row); } }
其他加载速度优化策略
DataTable层面优化
- 提前定义好DataTable的列结构,不要让运行时自动推断类型
- 写入过程中始终用
BeginLoadData/EndLoadData包裹,禁用行变更、索引更新等临时通知,写入速度可以提升数倍 - 批量添加行时,优先用
LoadDataRow或者一次性传入数组的方式,避免逐行Add的额外开销
XML读取层面优化
- 如果性能要求更高,可以放弃
XDocument改用XmlReader流式读取,不需要加载整个DOM到内存,内存占用和读取速度都会有30%~50%的提升 - 可以提前验证XML结构,跳过不需要的节点读取,减少不必要的解析开销
- 如果性能要求更高,可以放弃
UltraGrid控件层面优化
- 绑定数据源前先调用
ultraGrid1.SuspendLayout()和ultraGrid1.DataBindingFlags &= ~DataBindingFlags.AutoRefresh,绑定完成后再恢复布局和自动刷新 - 关闭不必要的自动排序、过滤、分组功能,等数据绑定完成后再开放给用户操作
- 绑定数据源前先调用
内容的提问来源于stack exchange,提问作者Fisher8370
相关产品推荐
相关产品推荐

