Ale*_*rt. 5 c# reflection performance delegates
我的目标是编写一个弱类型的 TryParse
方法,它基本上支持所有可用的struct类型(int,long,float ...)
public static bool TryParse(Type type, string s, out object obj)
Run Code Online (Sandbox Code Playgroud)
该实现将调用所TryParse
提供type
参数的方法(如果是int
,int.TryPase
则将调用type ,并将out值作为对象返回).
我通过反射实现了它,但是有一个主要的性能损失(正如我预期的那样)
反思实施:
public static class ParserHelper
{
public delegate bool TryParseDl(string str, out object obj);
private static readonly HashSet<Type> ParsableStructs = new HashSet<Type>
{
typeof(int),
typeof(uint),
typeof(decimal),
typeof(short),
typeof(ushort),
typeof(double),
typeof(long),
typeof(ulong),
typeof(float),
typeof(byte),
typeof(sbyte)
};
public static readonly ReadOnlyDictionary<Type, TryParseDl> StructParsers;
static ParserHelper()
{
StructParsers = new ReadOnlyDictionary<Type, TryParseDl>(CreateParsersForStructs());
}
/// Creates parsers for structs
private static Dictionary<Type, TryParseDl> CreateParsersForStructs()
{
var parsers = new Dictionary<Type, TryParseDl>();
foreach (var t in ParsableStructs)
{
parsers[t] = GetParserForStruct(t);
}
return parsers;
}
private static TryParseDl GetParserForStruct(Type targetType)
{
var methodInfo = targetType.GetMethod(
"TryParse",
BindingFlags.Public | BindingFlags.Static,
Type.DefaultBinder,
new[] { typeof(string), targetType.MakeByRefType() },
null);
return (string str, out object obj) =>
{
if (string.IsNullOrEmpty(str))
{
obj = targetType.IsValueType ? Activator.CreateInstance(targetType) : null;
return true;
}
var inputParameters = new object[] { str, null };
var tryParseResult = (bool)methodInfo.Invoke(null, inputParameters);
obj = inputParameters[1];
return tryParseResult;
};
}
}
Run Code Online (Sandbox Code Playgroud)
这是性能测试:
public class Program
{
public static void Main()
{
Stopwatch s = new Stopwatch();
string str = "100";
s.Start();
for(int j = 0;j<100;j++)
{
int i;
int.TryParse(str,out i);
}
s.Stop();
Console.WriteLine(s.Elapsed);
s.Reset();
s.Start();
var parser = ParserHelper.StructParsers[typeof(int)];
for(int j = 0;j<100;j++)
{
object o;
parser(str, out o);
}
s.Stop();
Console.WriteLine(s.Elapsed);
}
}
Run Code Online (Sandbox Code Playgroud)
平均结果是反射调用比直接调用慢了200倍(在100次重复上).演示反射测试的小提琴
我试图通过使用缓存的委托来提高性能:
public static class StructParserExtensions
{
public static bool IntToObjParse(string str, out object obj)
{
int i;
var result = int.TryParse(str, out i);
obj = result ? (object)i : null;
return result;
}
public static bool LongToObjParse(string str, out object obj)
{
long i;
var result = long.TryParse(str, out i);
obj = result ? (object)i : null;
return result;
}
//implementations for other types goes here
}
public static class ParserHelper
{
public delegate bool TryParseDl(string str, out object obj);
public static readonly ReadOnlyDictionary<Type, TryParseDl> StructParsers;
static ParserHelper()
{
StructParsers = new ReadOnlyDictionary<Type, TryParseDl>(CreateParsersForStructs());
}
/// Creates parsers for structs
/// </summary>
/// <returns>Dictionary</returns>
private static Dictionary<Type, TryParseDl> CreateParsersForStructs()
{
var parsers = new Dictionary<Type, TryParseDl>();
parsers[typeof(int)] = StructParserExtensions.IntToObjParse;
parsers[typeof(long)] = StructParserExtensions.LongToObjParse;
return parsers;
}
}
Run Code Online (Sandbox Code Playgroud)
我假设使用委托将大大提高性能,因此它将接近直接调用,但我错了它仍然慢约100倍(在100 reties) 这里是小提琴
我的问题是:
你只是测试100次迭代.您主要测试一次性启动开销.增加迭代次数,直到每次测试需要1秒钟.这样,开销就会消失在噪音中.
目前,您的代码运行时间为.5毫秒.这远远在噪音范围内.修好后我得到:
00:00:00.9711365
00:00:01.0958751 //Slightly slower
Run Code Online (Sandbox Code Playgroud)
该基准使用1e7次迭代,而前一次使用1e2.另外,请确保在Release模式下进行测试,而不需要调试器附加您关注的位数.
归档时间: |
|
查看次数: |
1979 次 |
最近记录: |