Ich verarbeite die Fix Meldungen mit hoher Intensität und muss die Eingabe -Fix -Nachrichtendaten effizient in ein Wörterbuch für die schnelle Suche umwandeln. Ich habe bereits einige Optimierungen versucht, z. B. die Verwendung von ReadOnlyspan anstelle von String , aber meine Benchmark-Ergebnisse sind immer noch unbefriedigend.
public class FixDictionaryBase
{
private readonly Dictionary _dict;
protected FixDictionaryBase()
{
_dict = [];
}
public string GetTag(int tag) => _dict.GetValueOrDefault(tag);
protected void Parse(ReadOnlySpan inputSpan, out List groups)
{
// Algorithm for processing FIX message string:
// 1. Iterate through the input string and extract key-value pairs based on the splitter character.
// 2. If the key is RptSeq (83), initialize a new group and add it to the groups list.
// 3. Assign key-value pairs to the appropriate dictionary:
// - If the key is 10 (Checksum), store it in the main _dict.
// - If currently inside a group, store it in the dictionary of the current group.
// - Otherwise, store it in the main _dict.
// 4. Continue processing until no more splitter characters are found in the input string.
groups = [];
FixDictionaryBase currentGroup = null;
// Special characters used to separate data
const char splitter = '\x01';
const char equalChar = '=';
const int rptSeq = 83;
// Find the first occurrence of the splitter character
int splitterIndex = inputSpan.IndexOf(splitter);
var hasGroup = false;
while (splitterIndex != -1)
{
// Extract the part before the splitter to get the key-value pair
var leftPart = inputSpan[..splitterIndex];
// Find the position of '=' to separate key and value
var equalIndex = leftPart.IndexOf(equalChar);
// Extract key from the part before '='
var key = int.Parse(leftPart[..equalIndex]);
// Extract value from the part after '='
var value = leftPart[(equalIndex + 1)..].ToString();
// If the key is RptSeq (83), start a new group and add it to the groups list
if (key == rptSeq)
{
hasGroup = true;
currentGroup = new();
groups.Add(currentGroup);
}
// Determine the appropriate dictionary to store data
// - If the key is 10 (Checksum), always store it in the main _dict
// - If a group has been identified (hasGroup == true), store it in the current group's dictionary
// - Otherwise, store it in the main _dict
var isChecksum = key == 10;
var currentDict = isChecksum ? _dict : hasGroup ? currentGroup._dict : _dict;
currentDict[key] = value;
// Remove the processed part and continue searching for the next splitter
inputSpan = inputSpan[(splitterIndex + 1)..];
splitterIndex = inputSpan.IndexOf(splitter);
}
}
}
public sealed class FixDictionary : FixDictionaryBase
{
private readonly string _fixString;
public FixDictionary(string fixString) : base()
{
_fixString = fixString;
Parse(fixString, out var groups);
Groups = groups;
}
public IReadOnlyList Groups { get; }
public string GetFixString() => _fixString;
}
< /code>
Benchmarkergebnisse < /h3>
Hier sind meine Benchmark-Ergebnisse mit Benchmarkdotnet: < /p>
BenchmarkDotNet v0.13.10, Windows 11 (10.0.26100.3476)
Intel Core i5-9400 CPU 2.90GHz (Coffee Lake), 1 CPU, 6 logical and 6 physical cores
.NET SDK 9.0.102
[Host] : .NET 8.0.12 (8.0.1224.60305), X64 RyuJIT AVX2
DefaultJob : .NET 8.0.12 (8.0.1224.60305), X64 RyuJIT AVX2
| Method | Mean | Error | StdDev | Gen0 | Gen1 | Allocated |
|----------- |---------:|----------:|----------:|-------:|-------:|----------:|
| GetFixData | 8.044 μs | 0.0683 μs | 0.0639 μs | 3.5553 | 0.1678 | 16.38 KB |
< /code>
Eingabebestand für Benchmark < /h3>
8=FIX.4.4[SOH]9=1087[SOH]35=X[SOH]49=VNMGW[SOH]56=99999[SOH]34=433615[SOH]52=20250325 06:00:02.273[SOH]30001=UPX[SOH]20004=G1[SOH]336=99[SOH]55=VN000000YTC0[SOH]75=20250311[SOH]60=060000346[SOH]30522=200[SOH]30524=2[SOH]268=20[SOH]83=1[SOH]279=0[SOH]269=1[SOH]290=1[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=2[SOH]279=0[SOH]269=0[SOH]290=1[SOH]270=33000.0[SOH]271=100[SOH]346=1[SOH]30271=0[SOH]83=3[SOH]279=0[SOH]269=1[SOH]290=2[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=4[SOH]279=0[SOH]269=0[SOH]290=2[SOH]270=31800.0[SOH]271=100[SOH]346=1[SOH]30271=0[SOH]83=5[SOH]279=0[SOH]269=1[SOH]290=3[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=6[SOH]279=0[SOH]269=0[SOH]290=3[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=7[SOH]279=0[SOH]269=1[SOH]290=4[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=8[SOH]279=0[SOH]269=0[SOH]290=4[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=9[SOH]279=0[SOH]269=1[SOH]290=5[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=10[SOH]279=0[SOH]269=0[SOH]290=5[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=11[SOH]279=0[SOH]269=1[SOH]290=6[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=12[SOH]279=0[SOH]269=0[SOH]290=6[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=13[SOH]279=0[SOH]269=1[SOH]290=7[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=14[SOH]279=0[SOH]269=0[SOH]290=7[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=15[SOH]279=0[SOH]269=1[SOH]290=8[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=16[SOH]279=0[SOH]269=0[SOH]290=8[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=17[SOH]279=0[SOH]269=1[SOH]290=9[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=18[SOH]279=0[SOH]269=0[SOH]290=9[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=19[SOH]279=0[SOH]269=1[SOH]290=10[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=20[SOH]279=0[SOH]269=0[SOH]290=10[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]10=103[SOH]
< /code>
mit [SOH] ist '\ x01' < /p>
Ziel < /H3>
Ich ziele darauf ab, mindestens 3 × die aktuelle Geschwindigkeit zu erreichen, während die Gedächtniszuteilung minimal bleibt. Leistung und niedrigere Speicherzuweisung? SIMD, Span
-basierte Analyse oder andere Optimierungen mit niedrigem Niveau in diesem Fall von Vorteil? geschätzt
Bearbeiten
Ich habe auch ein Bild meiner Fix -Zeichenfolge angehängt, um Klarheit zu gewährleisten:
Ich verarbeite die Fix Meldungen mit hoher Intensität und muss die Eingabe -Fix -Nachrichtendaten effizient in ein Wörterbuch für die schnelle Suche umwandeln. Ich habe bereits einige Optimierungen versucht, z. B. die Verwendung von ReadOnlyspan anstelle von String , aber meine Benchmark-Ergebnisse sind immer noch unbefriedigend.[code]public class FixDictionaryBase { private readonly Dictionary _dict;
protected FixDictionaryBase() { _dict = []; }
public string GetTag(int tag) => _dict.GetValueOrDefault(tag);
protected void Parse(ReadOnlySpan inputSpan, out List groups) { // Algorithm for processing FIX message string: // 1. Iterate through the input string and extract key-value pairs based on the splitter character. // 2. If the key is RptSeq (83), initialize a new group and add it to the groups list. // 3. Assign key-value pairs to the appropriate dictionary: // - If the key is 10 (Checksum), store it in the main _dict. // - If currently inside a group, store it in the dictionary of the current group. // - Otherwise, store it in the main _dict. // 4. Continue processing until no more splitter characters are found in the input string.
groups = [];
FixDictionaryBase currentGroup = null;
// Special characters used to separate data const char splitter = '\x01'; const char equalChar = '='; const int rptSeq = 83;
// Find the first occurrence of the splitter character int splitterIndex = inputSpan.IndexOf(splitter); var hasGroup = false;
while (splitterIndex != -1) { // Extract the part before the splitter to get the key-value pair var leftPart = inputSpan[..splitterIndex];
// Find the position of '=' to separate key and value var equalIndex = leftPart.IndexOf(equalChar);
// Extract key from the part before '=' var key = int.Parse(leftPart[..equalIndex]);
// Extract value from the part after '=' var value = leftPart[(equalIndex + 1)..].ToString();
// If the key is RptSeq (83), start a new group and add it to the groups list if (key == rptSeq) { hasGroup = true; currentGroup = new(); groups.Add(currentGroup); }
// Determine the appropriate dictionary to store data // - If the key is 10 (Checksum), always store it in the main _dict // - If a group has been identified (hasGroup == true), store it in the current group's dictionary // - Otherwise, store it in the main _dict var isChecksum = key == 10; var currentDict = isChecksum ? _dict : hasGroup ? currentGroup._dict : _dict; currentDict[key] = value;
// Remove the processed part and continue searching for the next splitter inputSpan = inputSpan[(splitterIndex + 1)..]; splitterIndex = inputSpan.IndexOf(splitter); } } }
public sealed class FixDictionary : FixDictionaryBase { private readonly string _fixString;
public FixDictionary(string fixString) : base() { _fixString = fixString; Parse(fixString, out var groups); Groups = groups; }
public IReadOnlyList Groups { get; }
public string GetFixString() => _fixString; } < /code> Benchmarkergebnisse < /h3> Hier sind meine Benchmark-Ergebnisse mit Benchmarkdotnet: < /p> BenchmarkDotNet v0.13.10, Windows 11 (10.0.26100.3476) Intel Core i5-9400 CPU 2.90GHz (Coffee Lake), 1 CPU, 6 logical and 6 physical cores .NET SDK 9.0.102 [Host] : .NET 8.0.12 (8.0.1224.60305), X64 RyuJIT AVX2 DefaultJob : .NET 8.0.12 (8.0.1224.60305), X64 RyuJIT AVX2
< /code> Eingabebestand für Benchmark < /h3> 8=FIX.4.4[SOH]9=1087[SOH]35=X[SOH]49=VNMGW[SOH]56=99999[SOH]34=433615[SOH]52=20250325 06:00:02.273[SOH]30001=UPX[SOH]20004=G1[SOH]336=99[SOH]55=VN000000YTC0[SOH]75=20250311[SOH]60=060000346[SOH]30522=200[SOH]30524=2[SOH]268=20[SOH]83=1[SOH]279=0[SOH]269=1[SOH]290=1[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=2[SOH]279=0[SOH]269=0[SOH]290=1[SOH]270=33000.0[SOH]271=100[SOH]346=1[SOH]30271=0[SOH]83=3[SOH]279=0[SOH]269=1[SOH]290=2[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=4[SOH]279=0[SOH]269=0[SOH]290=2[SOH]270=31800.0[SOH]271=100[SOH]346=1[SOH]30271=0[SOH]83=5[SOH]279=0[SOH]269=1[SOH]290=3[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=6[SOH]279=0[SOH]269=0[SOH]290=3[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=7[SOH]279=0[SOH]269=1[SOH]290=4[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=8[SOH]279=0[SOH]269=0[SOH]290=4[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=9[SOH]279=0[SOH]269=1[SOH]290=5[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=10[SOH]279=0[SOH]269=0[SOH]290=5[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=11[SOH]279=0[SOH]269=1[SOH]290=6[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=12[SOH]279=0[SOH]269=0[SOH]290=6[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=13[SOH]279=0[SOH]269=1[SOH]290=7[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=14[SOH]279=0[SOH]269=0[SOH]290=7[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=15[SOH]279=0[SOH]269=1[SOH]290=8[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=16[SOH]279=0[SOH]269=0[SOH]290=8[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=17[SOH]279=0[SOH]269=1[SOH]290=9[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=18[SOH]279=0[SOH]269=0[SOH]290=9[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=19[SOH]279=0[SOH]269=1[SOH]290=10[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]83=20[SOH]279=0[SOH]269=0[SOH]290=10[SOH]270=0.0[SOH]271=0[SOH]30271=0[SOH]10=103[SOH] < /code> mit [SOH] ist '\ x01' < /p> Ziel < /H3> Ich ziele darauf ab, mindestens 3 × die aktuelle Geschwindigkeit zu erreichen, während die Gedächtniszuteilung minimal bleibt. Leistung und niedrigere Speicherzuweisung? SIMD, Span [/code] -basierte Analyse oder andere Optimierungen mit niedrigem Niveau in diesem Fall von Vorteil? geschätzt Bearbeiten Ich habe auch ein Bild meiner Fix -Zeichenfolge angehängt, um Klarheit zu gewährleisten:
Ich entworfene eine Android -E -Mail -Anwendung und benötige eine effiziente Synchronisierungsstrategie, die die Akkulaufzeit, die Netzwerkverwendung und die Konsistenz ausgleichen und gleichzeitig...
Ich programmiere einen Physiksimulator zur Simulation des statischen Verhaltens von im Wasser schwimmenden Objekten (hauptsächlich Schiffe). Die Objektposition wird durch die Eintauchtiefe...
Ich versuche zu verstehen, wie der lokale Dominator radiusbasierte Analyse durchführt. Nach meinem Verständnis wird ein bestimmter Radius in ein Raster aufgeteilt, und jede Rasterzelle trifft eine...