在.NET中解析FIX协议消息的最有效方法是什么?

Ste*_*son 8 .net finance fix-protocol

我遇到了这个非常相似的问题,但该问题被标记为QuickFIX(与我的问题无关),大多数答案都与QuickFIX相关.

我的问题更广泛.我正在寻找使用C#解析FIX协议消息最有效方法.作为背景,FIX消息由一系列由ASCII <SOH>字符(0x01)分隔的标记/值对组成.消息中的字段数是可变的.

示例消息可能如下所示:

8=FIX.4.2<SOH>9=175<SOH>35=D<SOH>49=BUY1<SOH>56=SELL1<SOH>34=2482<SOH>50=frg<SOH>
52=20100702-11:12:42<SOH>11=BS01000354924000<SOH>21=3<SOH>100=J<SOH>55=ILA SJ<SOH>
48=YY77<SOH>22=5<SOH>167=CS<SOH>207=J<SOH>54=1<SOH>60=20100702-11:12:42<SOH>
38=500<SOH>40=1<SOH>15=ZAR<SOH>59=0<SOH>10=230<SOH>
Run Code Online (Sandbox Code Playgroud)

对于每个字段,标记(整数)和值(对于我们的目的,字符串)由'='字符分隔.(每个标签的精确语义都在协议中定义,但这与这个问题没有特别密切关系.)

通常的情况是,在进行基本解析时,您只对来自FIX标头的少数特定标签感兴趣,而不是真正对每个可能的字段进行随机访问.我考虑的策略包括:

  • 使用String.Split,遍历每个元素并将标记放入Hashtable中的索引映射 - 如果需要,在某些时候提供对所有字段的完全随机访问

  • (轻微优化)使用String.Split,扫描数组中感兴趣的标签并将标记放入索引映射到另一个容器(不一定是Hashtable,因为它可能是相当少量的项目,并且在解析之前已知项目数)

  • 使用字段扫描消息字段String.IndexOf并在适当的结构中存储感兴趣的字段的偏移量和长度

关于前两个 - 虽然我的测量表明String.Split速度非常快,但根据文档,该方法为结果数组的每个元素分配一个新的String,如果您正在解析大量消息,它会产生大量垃圾.谁能看到更好的方法来解决.NET中的这个问题?

编辑:

我遗漏的三条重要信息:

  1. 标签在FIX消息中不一定是唯一的,即在某些情况下可能出现重复标签.

  2. 某些类型的FIX字段可以<SOH>在数据中包含"嵌入" - 这些标记被称为"数据"类型 - 字典列出了此类型的标记号.

  3. 最终的要求是能够编辑消息(特别是替换值).

Ale*_*xis 8

假设您通过网络获取这些消息,或者从磁盘加载它们.在任何一种情况下,您都可以将它们作为字节数组访问,并以正向读取方式读取字节数组.如果你想要/需要/需要高性能,那么自己解析字节数组(为了高性能,不要使用标签和值的散列表字典,因为这比较慢).自己解析字节数组也意味着您可以避免使用您不感兴趣的数据,并且可以优化解析以反映这一点.

您应该能够轻松避免大多数对象分配.您可以非常轻松地解析FIX浮点数据类型,而无需创建对象(您可以在此处使用自己的版本大大超出double.parse).您可能需要考虑的唯一标签值是字符串,例如FIX中的符号值.为了避免在这里创建字符串,您可以想出一种简单的方法来确定每个符号的唯一int标识符(这是一种值类型),这将再次帮助您避免在堆上进行分配.

正确完成的消息的自定义优化解析应该轻松胜过QuickFix,您可以在.NET或Java中完成所有垃圾收集.


dig*_*All 3

我肯定会开始实施你的第一种方法,因为它听起来很清晰而且很容易做到。

ADictionary<int,Field>对我来说似乎非常好,可能包含在一个FixMessage公开方法的类中,比如GetFieldHavingTag(int tag)等等......

我不知道 FIX 协议,但看你的例子似乎消息通常很短,字段也很短,所以内存分配压力应该不是问题。

当然,确定一种方法是否适合您的唯一方法是实施并测试它。

如果您发现该方法在处理大量消息时速度很慢,请对其进行分析并找出问题所在/位置。

如果你不能轻松解决它,那么是的,改变策略,但我想强制执行这样的想法:你需要首先测试它,然后分析它并最终改变它。

因此,让我们想象一下,在第一次实现之后,您注意到在有很多消息的情况下,大量的字符串分配会降低您的性能。

那么是的,我会采取类似于你的第三种方法的方法,我们称之为“按需/惰性方法”。

我将构建一个FixMessage接受字符串消息的类,并且在需要任何消息字段之前不执行任何操作。
在这种情况下,我将使用IndexOf(或类似的东西)来搜索请求的字段,也许在另一个相同请求的情况下缓存结果会更快。