丨性能提升10倍的秘诀必须用好table_第1页
丨性能提升10倍的秘诀必须用好table_第2页
丨性能提升10倍的秘诀必须用好table_第3页
丨性能提升10倍的秘诀必须用好table_第4页
丨性能提升10倍的秘诀必须用好table_第5页
已阅读5页,还剩7页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

其二,在标准IT和OpenRyIT分支中,table这就形成了比较高的认知壁垒,导致了两极分化的结果——资深的OpenResty开发者能够写出很高性能的代码,而刚的则会怀疑OpenResty的高性能是不是一个。当然,等你学习完这节课的内容,你就可以轻松地戳破这层窗户纸,让性能提升10倍不是梦。在详细介绍table优化之前,先强调的一点是,table相关的优化,有一个自己的简单尽量复用,避免不必要的table创建你先记住这一点,下面,我们就从table的创建、元素的插入、清空、循环使用等方面,分第一步,自然是创建数组。在Lua中,我们创建数组的方式很简单代码1localt=代码localcolor={first="red","blue",third="green",涉及到数组的空间分配、resize和rehash。浪费一部分的内存空间,但多次的空间分配、resize和rehash等动作,就可以合并为事实上,LuaJIT中的table.new(narray,nhash)函数,就是因此而新增是它的两个参数narray和nhash的含义。下面我们通过一个简单的例子,来看下具体的使用。因为这个函数是LuaJIT展出来的,所以,在使用它之前,我们需要先require一下:代码localnew_tab=requirelocalt=new_tab(100,fori=1,100t[i]=另外,因为之前的OpenResty并没有完全绑定LuaJIT,还支持标准Lua,所以有些旧的代码会做这方面的兼容。如果没有找到table.new这个函数,就会模拟出来一个空的函代码localok,new_tab=pcall(require,ifnotoknew_tab=function(narr,nrec)return{}自己计算table有了table象之后,下一步就是向它里面增加元素了。最直接的方法,就是调用table.insert这个函数来插入元素:代码localnew_tab=requirelocalt=new_tab(100,fori=1,100table.insert(t,或者是先获取当前数组的长度,通过下标的方式来插代码localnew_tab=requirelocalt=new_tab(100,fori=1,100 t[#t+1]= 不过,这两种方式都需要先计算数组的长度,然后再新增元素。显然,这个操作是O(n时间复杂度。就拿上面代码的例子来说,for循环会计算100次数组的长度,这样下来性这一点又该如何解决呢?让我们看下lua-resty-redis这个的库是如何做的吧代码localfunctionlocalnargs=34localreq=new_tab(nargs*5+1,req[1]="*"..nargs..localnbits=89fori=1,nargslocalarg=req[nbits]=req[nbits+1]=req[nbits+2]=req[nbits+3]=req[nbits+4]=nbits=nbits+

return这个函数预先生成了数组req,它的大小由函数的入参来决定,这样就可以保证尽量不浪然后,它使用nbits这个变量,来自己req的下标,自然就抛弃了Lua内置的table.insert函数和获取长度的操作符#。你可以看到,在for循环中,nbits+1等一些运算,就是直接用下标的方式插入元素;并在最后用nbits=nbits+5,让下标保持这种的好处很明显,它省略了获取数组大小这个O(n)的操作,而是直接用下标,时间复杂度也变成了O(1)。当然,缺点也一样明显,那就是降低了代码的可读性,并且出错概循环使用单个既然table这么来之不易,我们自然要好好珍惜,尽量做到重复使用。不过,循环利用也是有条件的。我们先要把table中原有的数据清理干净,以免对下一个使用者造成污染。这时,table.clear函数就派上用场了。从它的名字你就能看出它的作用,它会把数组中的所有数据清空,但数组的大小不会变。也就是说,你用table.new(narray,nhash)生了一个长度为100的数组,clear后,长度还是100。为了让你能够更清楚它的实现,下面我给出了一个代码示例,它兼容了标准代码localok,clear_tab=pcall(require,ifnotokclear_tab=functionfork,_inpairs(tab)tab[k]=可以看到,clear函数实际上就是把每一个元素都置为了nil一般来说,我们会把这种循环使用的table,放在一个模块的toplevel中。这样,在你使用模块中的函数的时候,就可以根据自己的实际情况来决定,到底是直接使用,还是clear比如我们来看一个实际应用的例子。下面这段伪代码取自开源的微服务API网APISIX,这是它在加载插件时候的逻代码locallocal_plugins=23function67locallocal_conf=localplugin_names=localprocessed=for_,nameinipairs(plugin_names)ifprocessed[name]==nilprocessed[name]=insert_tab(local_plugins,return你可以看到,oapuins这个数组,是plugintopvel变量。在d这个加载插件函数的开始位置,table就会被清空,然后根据当前的情况生成新的插件列table到现在,你就掌握了对单个table循环使用的优化方法了。那么更进一步,你还可以用缓存池的方式来保存多个table,以便随用随取,提供的lua-tablepool正是出于这个下面这段代码,展示了table池的基本使用方法。我们可以从指定的池子中获取一table,使用完以后再释放回代码localtablepool=requirelocaltablepool_fetch=localtablepool_release=45localpool_name=localfunctionlocalt=tablepool_fetch(pool_name,10,----usingtforsometablepool_release(pool_name,tablepool中会用到前面我们介绍过的几个方法,而且它的代码只有不到一百行,所以,如果你学有余力,我十分推荐你可以自己搜索并研究一下。这里,我主要介绍下它的两个AP。第一个是fetch方法,它的参数和table.new基本一样,只是多了一个pool_name。如果池子中没有空闲的数组,fetch方法就会调用table.new来新建一个数组。代码tablepool.fetch(pool_name,narr,第二个是release个把table回池子的函数。在它的参数中,最后的no_clear,用来配置是否要调用table.clear把数组清空。代码tablepool.release(pool_name,tb,你看,我们前面介绍到的方法,到这里是不是就全部串联起来不过,注意不要因此tablepool。tablepool在实际项目中的使用并不多,比如Kong中就没有用到,APISIX也数几个调用。大多数情况下,不用tablepool的这层封性能优化,是OpenResty的硬骨头,也是我们大家关注的热点。今天我介绍了table最后给你留一个作业题:你可以自己做个性能测试,

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论