我想在多个并发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.129ms,而编码本身需要的时间少于.006ms。 (仅供参考,编解码器是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)执行视图模型外部的所有加密,在任何地方实现使用了viewmodel。
答案 0 :(得分:1)
访问HttpContext.Current.Items的性能成本真的是一个问题,或者你只是在猜测?根据您提供的数字和您提出的问题中的数字,然后在链接的问题中的数字不应该是: - 单次初始化为129 ms,1000次迭代为6 ms - HttpContext在10K次迭代中占用0.1ms(即在你的情况下为0.01)
线程静态是一个坏主意。虽然它可能会起作用,但您将来也无法使用异步控制器和类似功能。