AdairXie Blog

坚持做对的事情,并把事情做对

Metatable 二三事

告别 Metatable 小白

对于很多 Luaer 来说,也许只有 table 才会有 metatable。其实这种认识是错误的。 实际上在 Lua 中,每个值都可以拥有一个元表。对 userdata 和 table 类型而言,其每个值都可以拥有独立的元表,也可以几个值共享一个元表。对于其他类型,一个类型的值共享一个元表。例如所有 number 类型的值会共享一个元表。而默认 Lua 只为 string 类型赋予了元表...

Lua 正确处理可变参数

一定要注意 table 中的 hole

为了在 Lua 里处理可变参数,我们可能会写下面这样的代码: local function args(...) if next({...}) then for _, v in ipairs{...} do print(v) end else print("empty var") end end ...

Lua string.find 中的 “坑”

我们的线上环境,ngx_lua api 都是以模块形式加载到 lua 级别的 vm 中,已达到最大性能。而且我们并没有使用传统的 “包” 的形式来加载(也就是 require "xx.xx.xx" ),而是直接以模块名为加载( require "xx" ),这就意味着我们需要不断的来动态设置 package.path 来配合 require 的机制。于是我们写了下面这个方法,来实现我们的需求...

OpenResty 中写日志的套路

记录日志很重要,套路同样更重要

在 OR 中为了方便调试,我们可能会用这样的方式来记录日志: local f = io.open("test.log", "a+") f:write(message .. "\n") f:close() 然而这种写法在大多数情况下,都是可以正常工作的。但是在高并发的系统上,尤其还是多 worker 的环境下,这样写日志是会串的,原因就是 io.open 自身的缓存机制(本质是 libc...

Goto in LuaJIT

吊炸天的 LuaJIT

Lua 在 5.2 之后的版本,加入了 goto 这个关键字,用来控制程序跳转到指定 label。我们可以利用这个特性,来模拟 continue 的实现。需要注意的是 goto 只能跳转到 label,而 ::name:: 的格式就可以设置一个 label。 for i=1,5 do if i == 3 then goto continue end ...

OpenResty 中的连接池

连接池常见问题排查

注:set_keepalive 和 close 互斥(一个 socket 对象不能执行多次 setkeepalive 操作,会报:连接已关闭) 连接池的大小是对每一个 nginx worker 而言的。如果有 N 个 worker,最多就会有 N * pool_size 个连接。比如设置 keepalive = 100,开始启动时候是 0 连接来一个请求,获取一个 socket(空...

tail call 到底有啥用?

来体验下 proper tail call 强大的威力

在聊今天这个话题之前,我们需要知道什么叫 tail call。先来看下,lua 程序设计是怎么定义的: 尾调用是一种类似在函数结尾的 goto 调用,当函数最后一个动作是调用另外一个函数时,我们称这种调用尾调用。例如: function f(x)     return g(x) end g 的调用是尾调用。 例子中 f 调用 g 后不会再做任何事情,这种情况下当被调用函数 g ...

利用 loadstring 实现模块动态加载

Lua 中模块的动态加载

先来看一段 snippet: do i = 32 local i = 0 f = loadstring("i = i + 1; print(i)") g = function () i = i + 1; print(i) end f() --> 33 g() --> 1 h = function () _G.i = _...

require 理解

Lua require 模块加载机制

在 lua 中加载的其他文件的代码,通常可以使用 dofile、loadfile、require 函数等来完成。其中 dofile 每次加载都要编译执行,效率比较低,所以不推荐使用;同样 loadfile 虽然只需编译一次,但是并没有把结果缓存到 lua vm 中;因而,我们这里总是推荐使用第三种方式 require。 require 能够避免多次重复加载模块,一个模块被加载后会被缓存到 ...

捋一捋 backlog 的作用

聊不完的 TCP/IP

我们知道在 socket 编程中,服务端需要经历 listen → bind → accept 这么几个过程;而客户端需要经历 connect → receive 的过程。其中服务端在 bind 的时候需要指定 backlog 的大小。网上的好多文章,感觉都没有讲清楚这个参数的作用,特在此好好捋一下。方便他人,同时也方便自己。 术语约定: 未完成:半开,处于 SYN_RCVD 状态...