我想跨多个并发 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;
}
}
但是在一个紧密的循环中运行仍然很浪费:HttpContext.Current 调用背后有多少计算?
似乎每个线程的解决方案可能比每个请求的解决方案更精确。任何与 ASP.NET 请求兼容的建议?
在 ASP 之外但仍在 .NET 空间中,一个人的答案是 ThreadStatic:使用 ThreadStatic 替换昂贵的本地人——好主意吗?. 但是,http://blog.idm.fr/2010/03/aspnet-thread-agility-or-why-threadstatic-should-not-be-used.html显然排除了 ASP.NET 中的解决方案。与我的类似问题有没有办法模仿 ThreadStatic 与 HttpContext.Current.Items 一起使用?没有回答。
编辑:如果我确保我的编解码器使用不与 I/O 操作交错,我似乎可以使用 ThreadStatic,但我不确定这有多安全。
我现在达到了,但我想到的其他一些方法包括 1)为具有 EncodedAttribute 的项目提供自定义序列化/反序列化,2)实现我自己的静态 TripleDES 单块加密器,没有实例初始化开销,3)反对我的偏好,将外部初始化的加密器传递给每个项目的构造函数,4)实现 IEncryptable 接口并在填充结果后重新枚举项目,5)执行视图模型外部的所有加密,在使用视图模型的任何地方都实现.