【问底】王帅:深入PHP内核(三)
以下这个例子就是这个原理的实现,插入65535个数据需要消耗30秒,而正常情况下仅需要0.01秒。
Inserting 65536 evil elements took 32.726480007172 seconds Inserting 65536 good elements took 0.014460802078247 seconds文章来源:
4. 操作哈希表的内部函数PHP的变量符号表是通过哈希表来维护,首先介绍一下再PHP扩展中如何创建一个新的变量。PHP变量介绍,请看我上一篇文章,《深入PHP内核 - 弱类型变量原理探究》。
Bucket的结构:
4) pDesctructor 哈希表析构的回调函数,当删除一个哈希表的时候,会调用。
免费订阅“CSDN云计算(左)和CSDN大数据(右)”微信公众号,实时掌握第一手云中消息,了解最新的大数据进展!
2. PHP的哈希表实现原理
哈希表的结构:
4) nNextFreeElement 下一个空元素的地址。
CSDN发布虚拟化、Docker、OpenStack、CloudStack、数据中心等相关云计算资讯, 分享Hadoop、Spark、NoSQL/NewSQL、HBase、Impala、内存计算、流计算、机器学习和智能算法等相关大数据观点,提供云计算和大数据技术、平台、实践和产业信息等服务。
哈希函数(Hash Function):将Key通过哈希函数,得到一个指向bucket的指针。MD5,SHA-1是我们在业务中常用的哈希函数。
桶(Bucket):在哈希表中,真正保存数据的容器。
哈希冲突(Hash Collision):两个不同的Key,经过哈希函数,得到同一个bucket的指针。
5) 如果发现新插入元素已经超过HashTable的nTableSize,自动扩容至2倍nTableSize,重新哈希后维护新的HashTable。
5. 哈希冲突(Hashtable Collisions)因为任何一个哈希表的长度都是有限制的,所以一定会发生键名不同,hash函数计算后得到相同的bucket位置。也就是key1 != key2,但是HASH(key1) = HASH(key2)。如下图2,在发生哈希冲突时(Hash Collision),最坏情况下,所有的键名全部冲突,哈希表会退化成双向链表,操作时间复杂度为O(n)。
键名(Key):在哈希函数转换前,数据的标识。
【导读】王帅在海量分布式Web系统有超过8年沉淀,主导过多个大型系统的架构设计,目前在腾讯企业SaaS团队。
关于作者:王帅,腾讯企业QQ SaaS团队Leader。
9) persistent 定义了hashtable是否能在多次request中获得持久存在。
6. 哈希碰撞攻击及解决在去年发现了PHP的哈希碰撞攻击漏洞,PHP5.3.9以下的版本都会受影响。我们在业务压力很重的情况下,还是最短时间内把运营服务器全部更新到5.3.13以上,防止通过PHP的哈希碰撞进行拒绝服务攻击。
5) persistent 对应HashTable.persistent,当设置为true的时候,不会在RSHUTDOWN阶段自动销毁。
3) 如果arBuckets[A]不存在,创建新的arBucket[A](INIT_DATA)。或哈希冲突情况下,在arBuckets[A]的链表中找不到Key。创建新的bucket(INIT_DATA),并把新的buckets放在arBucket[A]链表头
我们通过更新哈希表的操作方式,来分析哈希表的操作机制:
3) pHashFunction 自定义哈希函数的钩子
7) arBuckets 实际存储Buckets的数组。
《问底》是CSDN云计算频道新建栏目,以实践为本,分享个人对于新时代软件架构与研发的深刻见解。在含有“【问底】”字样标题的文章中,你会看到某个国外IT巨头的架构分享,会看到国内资深工程师对某个技术的实践总结,更会看到一系列关于某个新技术的探索。《问底》邀请对技术具有独特/深刻见解的你一起打造一片只属于技术的天空,详情可邮件至zhonghao@csdn.net。在分析PHP中HashTable实现原理之前,先介绍一下相关的基本概念:
ZEND_FUNCTION(variable_creation) { zval *new_var1, *new_var2, *new_var3; //创建两个新的变量容器 char *string_contents = "This is a new string variable"; MAKE_STD_ZVAL(new_var1); //为new_var1申请空间并初始化 MAKE_STD_ZVAL(new_var2); ZVAL_LONG(new_var1, 10); //设置new_var1并赋值为long ZVAL_LONG(new_var2, 5); ZVAL_STRINGL(new_var3, string_contents, sizeof(string_contents), 0); //设置new_var3为字符串 ZEND_SET_SYMBOL(EG(active_symbol_table), "local_variable", new_var1); //设置long_variable为函数variable_creation的局部变量 ZEND_SET_SYMBOL(&EG(symbol_table), "global_variable", new_var2); //设置global_variable为全局变量 zend_hash_update( &EG(symbol_table), "new_var3", strlen("new_var3") + 1, &new_var3, sizeof(zval *), NULL ); RETURN_NULL(); }这里的zend_hash_update会更新变量符号表。PHP的数组也是用哈希表来维护,下面通过操作一个array来解释如何使用哈希表来才做数组。