【发布时间】:2012-08-08 13:57:14
【问题描述】:
我想跨多个并发 ASP.NET 请求使用非线程安全编码器实例池,而无需重新初始化它们。如果我不关心初始化成本,我会这样做:
public class ResultController {
public JsonResult GetResults() {
List<MyViewModel> items = new List<MyViewModel>();
// It obviously does more than this in real life
for(id = 0; id < 1000; id++) {
items.Add(new MyViewModel(id));
}
return Json(items);
}
}
public class MyViewModel() {
public string CodedId { get; set; }
public MyViewModel(int id) {
// This "new" is the concern
CodedId = new ExpensiveToInitializeCodec().InexpensiveEncode(id);
}
}
工作正常。所有本地人,不用担心线程,在我的模型之外没有人需要了解该值是编码的。然而,一个快速的性能测试表明,每次初始化大约需要 0.129 毫秒,而编码本身需要不到 0.006 毫秒。 (仅供参考,编解码器是 TripleDESCryptoServiceProvider)。
我想在不传递预初始化对象的情况下限制初始化成本(例如传入构造函数以提高性能,但会破坏关注点分离)。这是我目前正在做的事情,在这个简单的例子之外它显然会变得混乱:
public class ResultController {
public JsonResult GetResults() {
List<MyViewModel> items = new List<MyViewModel>();
ExpensiveToInitializeCodec codec = new ExpensiveToInitializeCodec();
for(id = 0; id < 1000; id++) {
items.Add(new MyViewModel(id, codec));
}
return Json(items);
}
}
public class MyViewModel() {
public string CodedId { get; set; }
public MyViewModel(int id, ExpensiveToInitializeCodec codec) {
CodedId = codec.InexpensiveEncode(id);
}
}
我可以利用众所周知的 ASP.NET 每请求缓存模式:
public class MyViewModel() {
public string CodedId { get; set; }
public MyViewModel(int id) {
CodedId = ExpensiveToInitializeCodec.Get().InexpensiveEncode(id);
}
}
public class ExpensiveToInitializeCodec {
public static ExpensiveToInitializeCodec Get() {
ExpensiveToInitializeCodec codec = HttpContext.Current.Items["codec"];
if (codec == null) {
codec = new ExpensiveToInitializeCodec();
HttpContext.Current.Items["codec"] = codec;
}
return codec;
}
}
但是在一个紧密的循环中运行仍然很浪费:How much computation is behind a HttpContext.Current call?
似乎每个线程的解决方案可能比每个请求的解决方案更精确。任何与 ASP.NET 请求兼容的建议?
在 ASP 之外但仍在 .NET 空间中,一个人的答案是 ThreadStatic: Using ThreadStatic to replace expensive locals -- good idea? 。但是,http://blog.idm.fr/2010/03/aspnet-thread-agility-or-why-threadstatic-should-not-be-used.html 显然排除了 ASP.NET 中的该解决方案。与我的Is there any way to imitate ThreadStatic for use with HttpContext.Current.Items? 类似的问题无人回答。
编辑:如果我确保我的编解码器使用不与 I/O 操作交错,我似乎可以使用 ThreadStatic,但我不确定这有多安全。
我现在达到了,但我想到的其他一些方法包括 1) 为具有 EncodedAttribute 的项目提供自定义序列化/反序列化,2) 实现我自己的静态 TripleDES 单块加密器,没有实例初始化开销, 3)根据我的喜好,将外部初始化的加密器传递给每个项目的构造函数,4)实现 IEncryptable 接口并在填充结果后重新枚举项目,5)执行视图模型外部的所有加密,在任何地方都实现使用了视图模型。
【问题讨论】:
-
你是什么意思:“没有传递预先初始化的对象(并打破分离)。”这是否意味着您不想要这些对象的“资源池”?如果不是,我不理解反对意见。
-
@ZeroBugBounce :不,这些对象的资源池会很好用。我不想要的是在父类中创建一个共享实用程序对象,只是将其传递给将附加到该父类的所有子类的初始化过程,从而牺牲对性能的关注点分离。这就是我目前正在做的事情。我有多个需要此功能的子类和多个父类,这是一个纠结。我添加了一个代码示例。
-
您是说父子之间的实际实例需要协调吗?如果没有,父母和孩子是否可以简单地从共享池中检查他们自己的实例并在完成后返回它们?或者,如果是这样,您是否有某种 IoC 容器可以根据每个请求完成协调结帐的工作?
-
@ZBB:不需要协调。工作对象池可能正是正确的解决方案。我从来没有建过一个。同步并没有吓到我,但在我看来,意外使其饱和将是很大的风险,需要小心谨慎并编写代码来防止。 stackoverflow.com/questions/2510975/… 。感谢您的想法,我正在阅读它。
标签: asp.net performance caching thread-safety