Согласитесь с Джоном, однако при обработке многих сообщений FIX это быстро складывается.
Метод ниже позволит учесть числа с пробелами. Если вам нужно обрабатывать десятичные дроби, то код будет немного другим. Разница в скорости между этими двумя методами составляет коэффициент 11. ConvertToLong приводит к 0 GC. Код ниже находится в C #:
///<summary>
///Converts a byte[] of characters that represent a number into a .net long type. Numbers can be padded from left
/// with spaces.
///</summary>
///<param name="buffer">The buffer containing the number as characters</param>
///<param name="startIndex">The startIndex of the number component</param>
///<param name="endIndex">The EndIndex of the number component</param>
///<returns>The price will be returned as a long from the ASCII characters</returns>
public static long ConvertToLong(this byte[] buffer, int startIndex, int endIndex)
{
long result = 0;
for (int i = startIndex; i <= endIndex; i++)
{
if (buffer[i] != 0x20)
{
// 48 is the decimal value of the '0' character. So to convert the char value
// of an int to a number we subtract 48. e.g '1' = 49 -48 = 1
result = result * 10 + (buffer[i] - 48);
}
}
return result;
}
/// <summary>
/// Same as above but converting to string then to long
/// </summary>
public static long ConvertToLong2(this byte[] buffer, int startIndex, int endIndex)
{
for (int i = startIndex; i <= endIndex; i++)
{
if (buffer[i] != SpaceChar)
{
return long.Parse(System.Text.Encoding.UTF8.GetString(buffer, i, (endIndex - i) + 1));
}
}
return 0;
}
[Test]
public void TestPerformance(){
const int iterations = 200 * 1000;
const int testRuns = 10;
const int warmUp = 10000;
const string number = " 123400";
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(number);
double result = 0;
for (int i = 0; i < warmUp; i++){
result = buffer.ConvertToLong(0, buffer.Length - 1);
}
for (int testRun = 0; testRun < testRuns; testRun++){
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < iterations; i++){
result = buffer.ConvertToLong(0, buffer.Length - 1);
}
sw.Stop();
Console.WriteLine("Test {4}: {0} ticks, {1}ms, 1 conversion takes = {2}μs or {3}ns. GCs: {5}", sw.ElapsedTicks,
sw.ElapsedMilliseconds, (((decimal) sw.ElapsedMilliseconds)/((decimal) iterations))*1000,
(((decimal) sw.ElapsedMilliseconds)/((decimal) iterations))*1000*1000, testRun,
GC.CollectionCount(0) + GC.CollectionCount(1) + GC.CollectionCount(2));
}
}
RESULTS
ConvertToLong:
Test 0: 9243 ticks, 4ms, 1 conversion takes = 0.02000μs or 20.00000ns. GCs: 2
Test 1: 8339 ticks, 4ms, 1 conversion takes = 0.02000μs or 20.00000ns. GCs: 2
Test 2: 8425 ticks, 4ms, 1 conversion takes = 0.02000μs or 20.00000ns. GCs: 2
Test 3: 8333 ticks, 4ms, 1 conversion takes = 0.02000μs or 20.00000ns. GCs: 2
Test 4: 8332 ticks, 4ms, 1 conversion takes = 0.02000μs or 20.00000ns. GCs: 2
Test 5: 8331 ticks, 4ms, 1 conversion takes = 0.02000μs or 20.00000ns. GCs: 2
Test 6: 8409 ticks, 4ms, 1 conversion takes = 0.02000μs or 20.00000ns. GCs: 2
Test 7: 8334 ticks, 4ms, 1 conversion takes = 0.02000μs or 20.00000ns. GCs: 2
Test 8: 8335 ticks, 4ms, 1 conversion takes = 0.02000μs or 20.00000ns. GCs: 2
Test 9: 8331 ticks, 4ms, 1 conversion takes = 0.02000μs or 20.00000ns. GCs: 2
ConvertToLong2:
Test 0: 109067 ticks, 55ms, 1 conversion takes = 0.275000μs or 275.000000ns. GCs: 4
Test 1: 109861 ticks, 56ms, 1 conversion takes = 0.28000μs or 280.00000ns. GCs: 8
Test 2: 102888 ticks, 52ms, 1 conversion takes = 0.26000μs or 260.00000ns. GCs: 9
Test 3: 105164 ticks, 53ms, 1 conversion takes = 0.265000μs or 265.000000ns. GCs: 10
Test 4: 104083 ticks, 53ms, 1 conversion takes = 0.265000μs or 265.000000ns. GCs: 11
Test 5: 102756 ticks, 52ms, 1 conversion takes = 0.26000μs or 260.00000ns. GCs: 13
Test 6: 102219 ticks, 52ms, 1 conversion takes = 0.26000μs or 260.00000ns. GCs: 14
Test 7: 102086 ticks, 52ms, 1 conversion takes = 0.26000μs or 260.00000ns. GCs: 15
Test 8: 102672 ticks, 52ms, 1 conversion takes = 0.26000μs or 260.00000ns. GCs: 17
Test 9: 102025 ticks, 52ms, 1 conversion takes = 0.26000μs or 260.00000ns. GCs: 18