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

C#查询XML文档symbol属性列表值的性能优化问题咨询

优化方案整理

1 一次性替代循环查询的最优方案

你当前场景下XML总节点仅7000个,总量极小,完全不需要多次执行XPath查询,最优方式是单次遍历所有item节点,匹配传入的symbol HashSet直接筛选,仅需扫描XML一次,时间复杂度O(7000),远低于循环查询的O(100*7000),也避免了拼接长XPath的语法风险和注入问题。

2 动态查询的编译能力利用

XPathExpression本身支持参数化扩展,需要搭配自定义XsltContext实现,但对你的场景性价比极低,更推荐两种更实用的方案:

  • 如果是高频查询场景:直接预编译整个XML到内存字典,不需要用到XPath编译能力,查询性能直接达到O(1)
  • 如果确实需要参数化XPath查询:可以将所有查询条件拼接后单次编译执行,100个or条件的XPath长度完全在可接受范围内,仅编译一次即可,不需要循环编译。

3 性能提升的其他建议

  • 优先做全量内存缓存:你的XML仅3-4M,全量加载到Dictionary<string, Info>内存占用不足10M,程序启动时或首次调用时加载一次即可,后续查询直接走内存字典,性能提升可达百倍以上。如果XML文件会更新,搭配FileSystemWatcher监听文件变更,变更后自动刷新缓存即可。
  • 若不使用缓存,优先用XmlReader流式读取:不需要加载整个DOM到内存,边读边匹配symbol,比XPathDocument内存占用更低、速度更快。
  • 避免重复操作:你现有代码每次循环都编译XPath表达式,编译开销远高于查询本身,即便保留循环查询逻辑,也建议拼接所有条件后单次编译执行。
  • 优化值解析:float.TryParse指定CultureInfo.InvariantCulture,既避免不同地区小数点格式解析错误,也能小幅提升解析性能。
优化代码示例

方案1:带缓存的最优实现(高频调用场景)

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Xml;

namespace Library
{
    public class Info
    {         
        public float Val1 { get; set; }
        public float Val2 { get; set; }
        public float Val3 { get; set; }
    }

    public class Technical
    {
        // 全局缓存
        private static Dictionary<string, Info> _cache;
        private static string _xmlPath;
        private static FileSystemWatcher _watcher;
        private static object _lockObj = new object();

        public Technical()
        {
            _xmlPath = Path.Combine(CommonObjects.Constant.SettingsFolderPath, CommonObjects.Constant.TechnicalFileName);
            // 初始化缓存和文件监听
            if (_cache == null)
            {
                RefreshCache();
                InitWatcher();
            }
        }

        private void RefreshCache()
        {
            lock (_lockObj)
            {
                var newCache = new Dictionary<string, Info>();
                using (var reader = XmlReader.Create(_xmlPath))
                {
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "item")
                        {
                            string symbol = reader.GetAttribute("symbol");
                            if (string.IsNullOrEmpty(symbol)) continue;

                            var info = new Info();
                            if (float.TryParse(reader.GetAttribute("val1"), NumberStyles.Float, CultureInfo.InvariantCulture, out float val1))
                                info.Val1 = val1;
                            if (float.TryParse(reader.GetAttribute("val2"), NumberStyles.Float, CultureInfo.InvariantCulture, out float val2))
                                info.Val2 = val2;
                            if (float.TryParse(reader.GetAttribute("val3"), NumberStyles.Float, CultureInfo.InvariantCulture, out float val3))
                                info.Val3 = val3;

                            newCache[symbol] = info;
                        }
                    }
                }
                _cache = newCache;
            }
        }

        private void InitWatcher()
        {
            _watcher = new FileSystemWatcher(Path.GetDirectoryName(_xmlPath), Path.GetFileName(_xmlPath));
            _watcher.Changed += (s, e) => RefreshCache();
            _watcher.EnableRaisingEvents = true;
        }

        public Dictionary<string, Info> SearchForSymbols(HashSet<string> symbolList)
        {
            var result = new Dictionary<string, Info>();
            if (symbolList.Count == 0 || _cache.Count == 0) return result;

            foreach (var symbol in symbolList)
            {
                if (_cache.TryGetValue(symbol, out Info info))
                {
                    result[symbol] = info;
                }
            }
            return result;
        }
    }
}

方案2:无缓存单次查询实现(低频调用场景)

public Dictionary<string, Info> SearchForSymbols(HashSet<string> symbolList)
{
    var result = new Dictionary<string, Info>();
    if (symbolList.Count == 0) return result;

    string xmlPath = Path.Combine(CommonObjects.Constant.SettingsFolderPath, CommonObjects.Constant.TechnicalFileName);
    using (var reader = XmlReader.Create(xmlPath))
    {
        while (reader.Read())
        {
            if (reader.NodeType == XmlNodeType.Element && reader.Name == "item")
            {
                string symbol = reader.GetAttribute("symbol");
                if (string.IsNullOrEmpty(symbol) || !symbolList.Contains(symbol)) continue;

                var info = new Info();
                if (float.TryParse(reader.GetAttribute("val1"), NumberStyles.Float, CultureInfo.InvariantCulture, out float val1))
                    info.Val1 = val1;
                if (float.TryParse(reader.GetAttribute("val2"), NumberStyles.Float, CultureInfo.InvariantCulture, out float val2))
                    info.Val2 = val2;
                if (float.TryParse(reader.GetAttribute("val3"), NumberStyles.Float, CultureInfo.InvariantCulture, out float val3))
                    info.Val3 = val3;

                result[symbol] = info;
                // 所有symbol都找到可提前退出
                if (result.Count == symbolList.Count) break;
            }
        }
    }
    return result;
}

内容的提问来源于stack exchange,提问作者WiredCordless

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 12:15:03