You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 21:36:03