我在我的一些库中使用 NLog ,即使我的用户没有 NLog dll,我也希望我的库能够工作/强>
到目前为止,我的解决方案是为我正在使用的类创建一个ILogger接口,如果找到了NLog dll,则使用反射从NLog调用方法。
问题是这种方法有时非常慢,导致我的CPU使用率增加了~10%(有些地方我做了大量的日志记录)。
我的问题是否有更通用的解决方案?也许使用发射使我没有这样的性能打击?似乎应该有一个简单的解决方案来解决这个问题。
答案 0 :(得分:0)
我认为您的解决方案是唯一可行的,即使用反射。 实际上,反射在计算方面更加昂贵。
答案 1 :(得分:0)
我的解决方案与LogLib类似的解决方案(由pepo发布)。
我的解决方案的反射部分导致了减速,所以我最终使用linq表达式创建了所有记录器方法的编译版本。这样,我在启动时的执行时间略有增加,但整个程序持续时间的执行时间更短(有时以天为单位)。
新版本(更快):
/// <summary>
/// Creates a method with one parameter of type TParam
/// </summary>
private static Action<object, TParam> CreateMethod<TParam>(Type targetType, string methodName)
{
MethodInfo methodInfo = targetType.GetMethod(methodName, new Type[] { typeof(TParam) });
ParameterExpression instance = Expression.Parameter(typeof(object), "inst");
ParameterExpression msg = Expression.Parameter(typeof(TParam), "p");
Expression callExpression = Expression.Call(
Expression.Convert(instance, targetType),
methodInfo,
msg);
Expression<Action<object, TParam>> methodExpression = Expression.Lambda<Action<object, TParam>>(callExpression, instance, msg);
Action<object, TParam> method = methodExpression.Compile();
return method;
}
/// <summary>
/// Creates a getter with the return type TReturn
/// </summary>
private static Func<object, TReturn> CreateGetter<TReturn>(Type targetType, string propertyName)
{
PropertyInfo propertyInfo = targetType.GetProperty(propertyName);
ParameterExpression instance = Expression.Parameter(typeof(object), "inst");
Expression callExpression = Expression.Property(
Expression.Convert(instance, targetType),
propertyInfo);
Expression<Func<object, TReturn>> methodExpression = Expression.Lambda<Func<object, TReturn>>(callExpression, instance);
Func<object, TReturn> property = methodExpression.Compile();
return property;
}
使用这种助手我存储方法的编译版本:
Action<object, string> trace = CreateMethod<string>(logger.GetType(), "Trace");
Func<object, bool> isTraceEnabled = CreateGetter<bool>(logger.GetType(), "IsTraceEnabled");
在我的包装器中,我调用这样的方法:
isTraceEnabled(logger);
trace(logger, "message")
这比旧版本复杂得多,我只想将记录器声明为动态
dynamic logger = ....
// ...
logger.IsTraceEnabled;
logger.Trace("message");
但在我的特殊情况下,加速是显而易见的。现在我的速度只有1%左右。我做了一些测量,结果发现其背后的实际原因是检查Trace是否启用的极端调用次数。在发布版本中,Trace已关闭,但我仍然有大约14个记录器,我必须经常探测IsTraceEnabled属性。
事后我可以缓存IsEnabled属性的值并获得类似的启动,但是哦......我注意到它有点迟了。