5 performance castle-dynamicproxy autofac dynamic-proxy
我今天才开始使用 DynamicProxy2。并发现它导致了显着的性能下降。
请参阅下面的代码。Test1 比 Test2 慢 10 倍。
使用 DynamicProxy 时有什么提高性能的技巧吗?
class Program
{
public void Main()
{
for (int i = 0; i < 3; i++)
{
var stopWatch = Stopwatch.StartNew();
int count = 1 * 1000 * 1000;
Test1(count);
//Test2(count);
long t = stopWatch.ElapsedMilliseconds;
Console.WriteLine(t.ToString() + " milliseconds");
Console.WriteLine(((double)count/(t/1000)).ToString() + " records/1 seconds");
}
}
void Test1(int count)
{
var builder = new ContainerBuilder();
builder.RegisterType<TestViewModel>()
.EnableClassInterceptors()
.InterceptedBy(typeof(NotifyPropertyChangedInterceptor));
builder.RegisterType<NotifyPropertyChangedInterceptor>();
var container = builder.Build();
for (int i = 0; i < count; i++)
{
container.Resolve<TestViewModel>();
}
}
void Test2(int count)
{
var builder = new ContainerBuilder();
builder.RegisterType<TestViewModel>();
var container = builder.Build();
for (int i = 0; i < count; i++)
{
container.Resolve<TestViewModel>();
}
}
}
public class TestViewModel : INotifyPropertyChanged
{
[Notify]
public virtual string Value { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
}
/// <summary>
/// Copied from: http://serialseb.blogspot.com/2008/05/implementing-inotifypropertychanged.html
/// </summary>
public class NotifyPropertyChangedInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
// let the original call go through first, so we can notify *after*
invocation.Proceed();
if (invocation.Method.Name.StartsWith("set_"))
{
string propertyName = invocation.Method.Name.Substring(4);
var pi = invocation.TargetType.GetProperty(propertyName);
// check that we have the attribute defined
if (Attribute.GetCustomAttribute(pi, typeof(NotifyAttribute)) == null)
return;
// get the field storing the delegate list that are stored by the event.
FieldInfo info = invocation.TargetType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic)
.Where(f => f.FieldType == typeof(PropertyChangedEventHandler))
.FirstOrDefault();
if (info != null)
{
// get the value of the field
PropertyChangedEventHandler evHandler = info.GetValue(invocation.InvocationTarget) as PropertyChangedEventHandler;
// invoke the delegate if it's not null (aka empty)
if (evHandler != null)
evHandler.Invoke(invocation.TargetType, new PropertyChangedEventArgs(propertyName));
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
更新:
在我的机器上,Test1 大约需要 45 秒,Test2 大约需要 4.5 秒。阅读Krzysztof Ko?mic的回答后,我尝试将NotifyPropertyChangedInterceptor放入单例范围:
builder.RegisterType<NotifyPropertyChangedInterceptor>().SingleInstance();
Run Code Online (Sandbox Code Playgroud)
这为我节省了大约 4 秒钟。现在 Test1 大约需要 41 秒。
更新 2:
Test3 在我的机器上大约需要 8.3 秒。所以看起来单独使用 Autofac 或 DynamicProxy 的性能不是一个很大的问题(在我的项目中),但是将它们组合在一起会导致性能大幅下降。
public void Test3(int count)
{
var generator = new Castle.DynamicProxy.ProxyGenerator();
for (int i = 0; i < count; i++)
{
generator.CreateClassProxy(typeof(TestViewModel),
new NotifyPropertyChangedInterceptor());
}
}
Run Code Online (Sandbox Code Playgroud)
你得到什么样的数字?在实际使用中性能下降是否明显?
我不熟悉 Autofac 如何在内部使用 DP,但您不应该注意到巨大的性能影响。
容器必须做更多的工作来代理虚拟机、实例化拦截器(因此您将创建两个对象,而不是只创建一个)并将拦截器与代理附加在一起。
如果缓存使用得当,当 DP 实际生成代理类型时,您将受到一次性性能影响。然后应该重用该类型。
您可以通过检查最后返回的代理的类型来轻松检查这一点。
如果是这样Castle.Proxies.TestViewModelProxy,则说明缓存工作正常。
如果是这样,Castle.Proxies.TestViewModelProxy_1000000那么您每次都会生成一个新的代理类型,这可以理解地降低您的性能。
一般来说,按照现实生活标准,性能影响应该可以忽略不计。
| 归档时间: |
|
| 查看次数: |
2861 次 |
| 最近记录: |