• 参加一个.NET培训后的若干笔记


    1. 上午老师提到一个thread必须隶属于某个appDomain,我觉得有点疑惑。简单在网上找了找,下面的关于soft thread和hard thread的阐述是我比较信服的:
    AppDomain是个静态概念,只是限定了对象的边界;线程是个动态概念,它可以运行在不同的AppDomain
    一个AppDomain内可以创建多个线程,但是不能限定这些线程只能在本AppDomain内执行代码。

    CLR中的System.Threading.Thread对象其实是个soft thread,它并不能被操作系统识别;操作系统能识别的是hard thread
    一个soft thread只属于一个AppDomain,穿越AppDomain的是hard thread。当hard thread访问到某个AppDomain,一个AppDomain就会为之产生一个soft thread

    hard threadthread local storage(TLS),这个存储区被CLR用来存储这个hard thread当前对应的AppDomain引用以及soft

    thread引用。当一个hard thread穿越到另外一个AppDomain时,TLS中的这些引用也会改变。

     

    2.关于程序集的“热插拔”

    杨老师提到过保持程序集对外接口稳定可以实现程序集的“热插拔”(即在不停止主应用程序的前提下,动态替换单个程序集)。下来查了一下,这种替换应该是 有很多条件的,因为.net不支持对单个程序集的Unload()操作,你必须把要替换的程序集放置在一个单独的AppDomain中运行,替换程序集的时候要杀掉这个AppDomain,在一个新的AppDomainLoad新版本的程序集。

    (AssemblyLoader.RemoteLoader)domain.CreateInstanceFromAndUnwrap(
                    "AssemblyLoader.dll","AssemblyLoader.RemoteLoader"); 

    所以,对这个程序集中方法的调用很多都将是跨边界的远程调用,性能上应该很成问题吧?有没有哪位同志以前在项目中这样用过?

     

    3.哈希/字典的底层结构是什么?其实就是数组,而根据key利用散列算法计算出来的hashcode自然成为了数组的下标。
    Hashtable用来存放数据的是bucket数组

    [StructLayout(LayoutKind.Sequential)]
    private struct bucket
    {
        
    public object key;
        
    public object val;
        
    public int hash_coll;
    }

    而Dictionary<TKey,TValue>用来存放数据的是Entry数组(里面多了一项next,同学们可以自己想想他用来做什么^_^)

    [StructLayout(LayoutKind.Sequential)]
    private struct Entry
    {
        
    public int hashCode;
        
    public int next;
        
    public TKey key;
        
    public TValue value;
    }

    既然是数组,那么这个数组应该申请多大长度呢?即便你在构造函数中进行了指定,.net也不会完全以你指定的为准,而是会从素数表里面找一个素数:

    private void Initialize(int capacity)
    {
        
    int prime = HashHelpers.GetPrime(capacity);
        
    this.buckets = new int[prime];
        
    for (int i = 0; i < this.buckets.Length; i++)
        {
            
    this.buckets[i] = -1;
        }
        
    this.entries = new Entry<TKey, TValue>[prime];
        
    this.freeList = -1;
    }

    那么如果你插入的数据量很大,预先申请的数组不够用了怎么办?扩容。
    扩容是个耗时非常惊人的内部操作,Hashtable 之所以写入效率仅为读取效率的 1/10 数量级, 频繁的扩容是一个因素。当进行扩容时,散列表内部要重新 new 一个更大的数组,然后把原来数组的内容拷贝到新数组,并进行重新散列。如何 new 这个更大的数组也有讲究。散列表的初始容量一般来讲是个素数。当扩容时,新数组的大小会设置成原数组双倍大小的相近的一个素数。为了避免生成素数的额外开销,.NET 内部有一个素数数组,记录了常用到的素数。如下所示:
    static HashHelpers()
    {
        primes 
    = new int[] { 
            
    37110x110x170x1d0x250x2f0x3b0x470x590x6b0x830xa30xc50xef
            
    0x1250x1610x1af0x2090x2770x2f90x3970x44f0x52f0x63d0x78b0x91d0xaf10xd2b0xfd10x12fd
            
    0x16cf0x1b650x20e30x27770x2f6f0x38ff0x446f0x521f0x628d0x76550x8e010xaa6b0xcc890xf5830x126a70x1619b
            
    0x1a8570x1fd3b0x263150x2dd670x3701b0x420230x4f3610x5f0ed0x721250x88e310xa443b0xc51eb0xec8c10x11bdbf0x154a3f0x198c4f
            
    0x1ea8670x24ca190x2c25c10x34fa1b0x3f928f0x4c49870x5b8b6f0x6dda89
         };
    }


    4. Delegate的序列化

    今天杨老师还谈到了代理序列化的问题。我们都知道代理后面可以挂一个很长的委托链,那序列化的时候这个委托链怎么办?google了一下,答案竟然是整个委托链都要被序列化,这就要求委托链上的每个对象都是可序列化的(要求很苛刻阿)。所以,delegate的序列化要慎用。对了,还查到一个有趣的结果,以前没注意到:

    delegate 开头是小写的 d,如果换成大写开头的 Delegate,那差别可就大了,简直是孙子和爷爷的区别。为什么说是孙子和爷爷呢?因为 delegate 仅仅是 C# 的关键字,表示一个继承自 System.MulticastDelegate 的具体委托类,而 Delegate 却是  System.MulticastDelegate 的父类,这还不是孙子和爷爷吗。另外,Delegate  System.MulticastDelegate 都是抽象类,只有编译器才可以从此类派生。也就是说,除了用 delegate 这种形式,我们不能显式地从这两个类派生。”

  • 相关阅读:
    Ubuntu 16.04 引导修复(Boot Repair)----lianwang----anzhuang windows hou(双系统修复一)
    安装openSUSE网卡驱动
    caffe2 安装与介绍
    虚云禅师经典佛教语录大全摘抄
    《百年虚云》经典台词
    anaconda的所有版本大全--下载地址
    caffe学习--caffe入门classification00学习--ipython
    caffe搭建--缺少 skimage-缺少 google.protobuf.internal.-caffe搭建--ipython--ubuntu16.04+ caffe+ ipython
    C#.NET开源项目、机器学习、Power BI (转载)
    caffe搭建--ubuntu标准平台的搭建
  • 原文地址:https://www.cnblogs.com/xingyukun/p/1541352.html
Copyright © 2020-2023  润新知