4

我想跨多个并发 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)执行视图模型外部的所有加密,在使用视图模型的任何地方都实现.

4

1 回答 1

1

访问 HttpContext.Current.Items 的性能成本真的是一个问题,还是您只是在猜测?根据你给出的数字和你给出的问题中的数字,然后是链接问题中的数字,它不应该是: - 单次初始化需要 129 毫秒 + 1000 次迭代需要 6 毫秒 - HttpContext 在 10K 迭代中需要 0.1 毫秒(即0.01 在你的情况下)

线程静态是一个坏主意。虽然它可能会起作用,但您将来将无法使用异步控制器和类似功能。

于 2012-08-08T21:23:19.440 回答