zoukankan      html  css  js  c++  java
  • 自定义Unity基于PerCall的生存期模型

    PerThreadLifetimeManager的问题

    使用Unity内置的PerThreadLifetimeManager生存期模型时,其基于ThreadStatic的TLS(Thread Local Storage)设计,也就是说对于每个托管的ManagedThreadId,其会缓存已生成的对象实例。

    由于CLR维护了托管线程池,使用过的线程并不会立即销毁,在需要的时候会继续复用。在类似ASP.NET PerCall或WCF PerCall条件下,当Call1在线程ManagedThreadId1中处理完毕后,Call2发生,而Call2很有可能也在线程ManagedThreadId1中处理。这种条件下Call2会自动复用处理Call1时生成并缓存的对象实例。

    如果我们希望每次调用(PerCall)都生成专用的对象实例,则PerThreadLifetimeManager在此种场景下不适合。

    解决办法有两种:

    1. 继续使用PerThreadLifetimeManager模型,不适用ThreadPool,而手动创建和销毁线程。
    2. 自定义对象生存期模型

    PerCallContextLifeTimeManager

        public class PerCallContextLifeTimeManager : LifetimeManager
        {
          private string _key = 
            string.Format(CultureInfo.InvariantCulture, 
            "PerCallContextLifeTimeManager_{0}", Guid.NewGuid());
    
          public override object GetValue()
          {
            return CallContext.GetData(_key);
          }
    
          public override void SetValue(object newValue)
          {
            CallContext.SetData(_key, newValue);
          }
    
          public override void RemoveValue()
          {
            CallContext.FreeNamedDataSlot(_key);
          }
        }

    使用举例

        private static void TestPerCallContextLifeTimeManager()
        {
          IExample example;
          using (IUnityContainer container = new UnityContainer())
          {
            container.RegisterType(typeof(IExample), typeof(Example),
              new PerCallContextLifeTimeManager());
    
            container.Resolve<IExample>().SayHello();
            container.Resolve<IExample>().SayHello();
    
            Action<int> action = delegate(int sleep)
            {
              container.Resolve<IExample>().SayHello();
              Thread.Sleep(sleep);
              container.Resolve<IExample>().SayHello();
            };
    
            Thread thread1 = new Thread((a) => action.Invoke((int)a));
            Thread thread2 = new Thread((a) => action.Invoke((int)a));
            thread1.Start(50);
            thread2.Start(55);
            thread1.Join();
            thread2.Join();
    
            ThreadPool.QueueUserWorkItem((a) => action.Invoke((int)a), 50);
            ThreadPool.QueueUserWorkItem((a) => action.Invoke((int)a), 55);
            Thread.Sleep(100);
    
            ThreadPool.QueueUserWorkItem((a) => action.Invoke((int)a), 50);
            ThreadPool.QueueUserWorkItem((a) => action.Invoke((int)a), 55);
            Thread.Sleep(100);
    
            ThreadPool.QueueUserWorkItem((a) => action.Invoke((int)a), 50);
            ThreadPool.QueueUserWorkItem((a) => action.Invoke((int)a), 55);
            Thread.Sleep(100);
    
            example = container.Resolve<IExample>();
          }
    
          example.SayHello();
    
          Console.ReadKey();
        }

  • 相关阅读:
    Tarjan算法求解桥和边双连通分量(附POJ 3352 Road Construction解题报告)
    无向图求点割集的算法
    hdu 2121无根最小树形图要建一个虚拟节点
    hdu 1576扩展欧几里得算法
    欧几里德算法的扩展-求解不定方程
    hdu 3072 强连通+缩点+最小树形图思想
    1352 集合计数 扩展欧几里德算法
    1247 可能的路径 逆向思维
    Atcoder B
    C. Timofey and a tree 观察题 + dfs模拟
  • 原文地址:https://www.cnblogs.com/gaochundong/p/unity_per_call_context_lifetime_manager.html
Copyright © 2011-2022 走看看