我认为在不使用本机代码的情况下能够实现的最有效的方法是使用不安全的代码。
private static IEnumerable<string> ExtractChunksUnsafe(string format, string data)
{
if(format.Length != data.Length)
throw new ArgumentException("Format length must match Data length");
if(data.Length == 0)
throw new ArgumentException("Invalid Data length");
char prevFormat = '\0';
char currentFormat = format[0];
var chunks = new List<string>();
var builder = new StringBuilder();
unsafe
{
fixed(char * indexer = data)
{
var index = -1;
while(data.Length > ++index)
{
prevFormat = currentFormat;
currentFormat = format[index];
if(currentFormat != prevFormat)
{
chunks.Add(builder.ToString());
builder.Clear();
}
builder.Append((*(indexer + index)));
}
chunks.Add(builder.ToString());
builder.Clear();
}
}
return chunks;
}
比较:
private static IEnumerable<string> ExtractChunks(string format, string data)
{
if(format.Length != data.Length)
throw new ArgumentException("Format length must match Data length");
if(data.Length == 0)
throw new ArgumentException("Invalid Data length");
char prevFormat = '\0';
char currentFormat = format[0];
var prevIndex = 0;
var index = 1;
var message = data.ToCharArray();
var chunks = new List<string>();
while(data.Length > index)
{
prevFormat = currentFormat;
currentFormat = format[index];
if(currentFormat != prevFormat)
{
chunks.Add(new string(message, prevIndex, index - prevIndex));
prevIndex = index;
}
index++;
}
chunks.Add(new string(message, prevIndex, index - prevIndex));
return chunks;
}
样本:
string format = "mzIIIICCssss";
string data = ".a9876NE9001";
var chunks = ExtractChunks(format, data);
foreach(var message in chunks)
{
Console.WriteLine(message);
}
基准:
string format = "mzIIIICCssss";
string data = ".a9876NE9001";
// Warmup CLR
ExtractChunksUnsafe(format, data);
ExtractChunks(format, data);
TimeSpan unsafeCode;
TimeSpan safeCode;
var timer = Stopwatch.StartNew();
for(int i = 0; i < 10000000; i++)
{
ExtractChunksUnsafe(format, data);
}
unsafeCode = timer.Elapsed;
timer.Restart();
for(int i = 0; i < 10000000; i++)
{
ExtractChunks(format, data);
}
safeCode = timer.Elapsed;
timer.Stop();
Console.WriteLine("Unsafe time {0}", unsafeCode);
Console.WriteLine("Safe time {0}", safeCode);
结果:
Unsafe time 00:00:04.8551136
Safe time 00:00:03.1786573
甚至修改 Unsafe 主体:
unsafe
{
fixed(char * indexer = data)
{
var prevIndex = 0;
var index = 1;
while(data.Length > index)
{
prevFormat = currentFormat;
currentFormat = format[index];
if(currentFormat != prevFormat)
{
chunks.Add(new string(indexer, prevIndex, index - prevIndex));
prevIndex = index;
}
index++;
}
chunks.Add(new string(indexer, prevIndex, index - prevIndex));
}
}
仍然会导致时间变慢Unsafe time 00:00:03.4565302
。