【分享】简单介绍lua语言
“袁承志知道若再谦逊,那就是瞧人不起,展开五行拳,发拳当胸打去。荣彩和旁观三人本来都以为他武功有独到之秘,哪知使出来的竟是武林中最寻常不过的五行拳。敌对三人登时意存轻视,温青脸上不自禁露出失望的神色。”
“荣彩心中暗喜,双拳如风,连抢三下攻势,满拟自己的大力魔爪手江南独步,三四招之间就可破去对方五行拳,那知袁承志轻描淡写的一一化解。再拆数招,荣彩暗暗吃惊,原来对方所使虽是极寻常的拳术,但每一招均是含劲不吐,意在拳先,举手抬足之间隐含极浑厚的内力。”
——金庸《碧血剑》
编程语言之于程序员,若武功招式之于习武之人,招式虽重要,却更在于使用之人。胜者之道,武功只行于表,高手用剑,片草只叶亦威力无穷。
当今武林,派别林立,语言繁杂,林林总总不计其数。主流文化的C/C++、Java、C#、VB;偏安一隅的Fortran;动态语言中的Perl、Tcl、Ruby、Forth、Python、PHP,以及本次介绍的Lua;……,等等等等。再加上世界上那些不知道躲在哪的旮旯的奇奇怪怪的hacker捣鼓出来的异想天开的语言,要想各类语言样样精通,不异于痴人说梦。不信可欣赏一下BrainFuck语言的Hello World程序,语言本身依如其名。-J-
>+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++++>-]<.#>+++++++++++[<+++++>-]<.>++++++++[<+++>-]<.+++.------.--------.[-]>++++++++[<++++>-]<+.[-]++++++++++.
虽说语言的威力依使用者本身的修为高低而定,但不同语言本身的设计又有不同。若让用Java写写操作系统内核、Perl写写驱动程序、C/C++写写web应用,都无异于舍近求远,好刀只用上了刀背。
Lua本身是以简单优雅为本,着眼于处理那些C不擅长的任务。借助C/C++为其扩展,Lua可闪现无穷魅力。Lua本身完全遵循ANSI C而写成,只要有C编译器的地方,Lua便可发挥她的力量。Lua不需要追求Python那样的大而全的库,太多累赘,反而破坏了她的优美。
语言的优美,来自于使用者自己的感悟。Lua的优雅,也只有使用后才会明白。
扬起帆,让我们一同踏上Lua的学习之旅……
附近为本次分享的ppt,希望能大致了解下lua是个啥,拥抱变化,做个灵活的程序员。
lua实现microtime扩展,提高math.randomseed力度
某个项目需要随机生成crypt相关的,当时用到randomseed是采用os.time(),果然与我考虑的一样,生成的随机很不理想,os.time()占一秒,跨越太大了,当然也考虑过利用闭包的模式,自增一个小数点,不过考虑到实用性,还是决定在原来的lua-mylib(现在改名为:lua-nix)中加入一个microtime,返回一个float数,增加了seed的跨越力度,这样重复的机会几乎没有,最后实现代码如下:
[cc lang='lua']
function generate_nonce()
--math.randomseed(os.time()) --seed力度不够
math.randomseed(nix.microtime()*1000000) -- better than before
return math.random()
end
[/cc]
扩展源码如下:
[cc lang='c']
……
#include
……
#define MICRO_IN_SEC 1000000.00
……
static int Lmicrotime (lua_State *L) {
struct timeval tp = {0};
if (gettimeofday(&tp, NULL)) {
lua_pushboolean(L, 0);
}
lua_pushnumber(L, (double)(tp.tv_sec + tp.tv_usec / MICRO_IN_SEC));
return 1;
}
……
[/cc]
具体可以参阅:http://alacner.com/pro/git/?a=summary&p=lua-nix
关于lua的闭包(Closure)和Upvalue
一般的文章都是从代码层面来分析lua中的闭包(closure)今天在我的U盘的lua的文章里找到了一篇算是从实现层进行了分析,还算是比较让人耳目一行,一看就明了了,所以不敢独享,赶紧贴上来给【必须哒】的博友分享,但是很不巧,我忘记了摘自哪里了,下次作者看到,勿怪!好,切入正题:
upvalue:嵌套函数的外部函数的局部变量
[cc lang='lua']
function func(a) --这个函数返回值是一个函数
return function ()
a = a + 1 --这里可以访问外部函数func的局部变量a,这个变量a就是upvalue
return a
end
end
[/cc]
func返回一个匿名函数,可用变量接取之。该匿名函数有一个upvalue a(有点像C函数的static变量),初值为首次调用func时的参数
闭包:一个匿名函数加上其可访问的upvalue
c = func(1) <== c现在指向一个拥有upvalue a = 1的匿名函数,c也被称作一个闭包
c() <== 返回2
c() <== 返回3
c2 = func(1) <== c2现在指向另外一个拥有upvalue a = 1的匿名函数,c2也被称作一个闭包
c2() <== 返回2
下面是示例代码:
[cc lang='c']
int
generatecclosure(lua_State *L) /* 闭包产生器 */
{
lua_pushnumber(L, 0); /* 压入第一个upvalue */
lua_pushnumber(L, 0); /* 压入第二个upvalue */
lua_pushcclosure(L, cclosure, 2); /* 压入闭包的同时也把upvalue置入该闭包的upvalue表 */
return 1; /* 返回闭包 */
}
int
cclosure(lua_State *L)
{
double upval1, upval2;
upval1 = lua_tonumber(L, lua_upvalueindex(1)); /* 注意upvalue索引1,2是闭包依赖的,不会和其他的闭包中的索引冲突 */
upval2 = lua_tonumber(L, lua_upvalueindex(2));
upval1++; upval2++;
lua_pushnumber(L, upval1); lua_replace(L, lua_upvalueindex(1));/* 更新upvalue1 */
lua_pushnumber(L, upval2); lua_replace(L, lua_upvalueindex(2));/* 更新upvalue2 */
lua_pushnumber(L, upval1 + upval2);
return 1;
}
int
generatecclosure2(lua_State *L)
{
lua_pushnumber(L, 10);
lua_pushnumber(L, 10);
lua_pushcclosure(L, cclosure2, 2);
return 1;
}
int
cclosure2(lua_State *L)
{
double upval1, upval2;
upval1 = lua_tonumber(L, lua_upvalueindex(1));
upval2 = lua_tonumber(L, lua_upvalueindex(2));
upval1++; upval2++;
lua_pushnumber(L, upval1); lua_replace(L, lua_upvalueindex(1));
lua_pushnumber(L, upval2); lua_replace(L, lua_upvalueindex(2));
lua_pushnumber(L, upval1 + upval2);
return 1;
}
然后向lua虚拟机注册一下全局函数:
lua_register(L, "generatecclosure", generatecclosure);
lua_register(L, "generatecclosure2", generatecclosure2);
[/cc]
最后执行main.lua:
[cc lang='lua']
c = generatecclosure()
c2 = generatecclosure2()
print(c()) -- 2
print(c()) -- 4
print(c2()) -- 22
print(c2()) -- 24
[/cc]
细究lua闭包->搞清本质才是王道
Lua中的函数是一阶类型值(first-class value),定义函数就象创建普通类型值相同(只不过函数类型值的数据主要是一条条指令而已),所以在函数体中仍然能定义函数。假设函数f2定义在函数 f1中,那么就称f2为f1的内嵌(inner)函数,f1为f2的外包(enclosing)函数,外包和内嵌都具有传递性,即f2的内嵌必然是f1的内嵌,而f1的外包也一定是f2的外包。内嵌函数能访问外包函数已创建的所有局部变量,这种特性便是所谓的词法定界(lexical scoping),而这些局部变量则称为该内嵌函数的外部局部变量(external local variable)或upvalue。试看如下代码:
[cc lang='lua']
function f1(n)
-- 函数参数也是局部变量
local function f2()
print(n) -- 引用外包函数的局部变量
end
return f2
end
g1 = f1(1979)
g1() -- 打印出1979
g2 = f1(500)
g2() -- 打印出500
[/cc]
当执行完g1 = f1(1979)后,局部变量n的生命本该结束,但因为他已成了内嵌函数f2(他又被赋给了变量g1)的upvalue,所以他仍然能以某种形式继续“存活”下来,从而令g1()打印出正确的值。
可为什么g2和g1的函数体相同(都是f1的内嵌函数f2的函数体),但打印值不同?这就涉及到一个相当重要的概念——闭包(closure)。事实上,Lua编译一个函数时,会为他生成一个原型(prototype),其中包含了函数体对应的虚拟机指令、函数用到的常量值(数,文本字符串等等)和一些调试信息。在运行时,每当Lua执行一个形如function...end 这样的表达式时,他就会创建一个新的数据对象,其中包含了相应函数原型的引用、环境(environment,用来查找全局变量的表)的引用及一个由所有 upvalue引用组成的数组,而这个数据对象就称为闭包。由此可见,函数是编译期概念,是静态的,而闭包是运行期概念,是动态的。g1和g2的值严格来说不是函数而是闭包,并且是两个不相同的闭包,而每个闭包能保有自己的upvalue值,所以g1和g2打印出的结果当然就不相同了。
使用upvalue非常方便,但他们的语义也非常微妙,需要引起注意。比如将f1函数改成:
[cc lang='lua']
function f1(n)
local function f2()
print(n)
end
n = n + 10
return f2
end
g1 = f1(1979)
g1() -- 打印出1989
[/cc]
内嵌函数定义在n = n + 10这条语句之前,可为什么g1()打印出的却是1989?upvalue实际是局部变量,而局部变量是保存在函数堆栈框架上(stack frame)的,所以只要upvalue还没有离开自己的作用域,他就一直生存在函数堆栈上。这种情况下,闭包将通过指向堆栈上的upvalue的引用来访问他们,一旦upvalue即将离开自己的作用域(这也意味着他马上要从堆栈中消失),闭包就会为他分配空间并保存当前的值,以后便可通过指向新分配空间的引用来访问该upvalue。当执行到f1(1979)的n = n + 10时,闭包已创建了,不过n并没有离开作用域,所以闭包仍然引用堆栈上的n,当return f2完成时,n即将结束生命,此时闭包便将n(已是1989了)复制到自己管理的空间中以便将来访问。弄清晰了内部的秘密后,运行结果就不难解释了。
upvalue还能为闭包之间提供一种数据共享的机制。试看下例:
[cc lang='lua'] function Create(n)
local function foo1()
print(n)
end
local function foo2()
n = n + 10
end
return foo1,foo2
end
f1,f2 = Create(1979)
f1() -- 打印1979
f2()
f1() -- 打印1989
f2()
f1() -- 打印1999
[/cc]
f1,f2这两个闭包的原型分别是Create中的内嵌函数foo1和foo2,而foo1和foo2引用的upvalue是同一个,即 Create的局部变量n。前面已说过,执行完Create调用后,闭包会把堆栈上n的值复制出来,那么是否f1和f2就分别拥有一个n的拷贝呢?其实不然,当Lua发现两个闭包的upvalue指向的是当前堆栈上的相同变量时,会聪明地只生成一个拷贝,然后让这两个闭包共享该拷贝,这样任一个闭包对该 upvalue进行修改都会被另一个探知。上述例子非常清晰地说明了这点:每次调用f2都将upvalue的值增加了10,随后f1将更新后的值打印出来。upvalue的这种语义非常有价值,他使得闭包之间能不依赖全局变量进行通讯,从而使代码的可靠性大大提高。
闭包在创建之时其upvalue就已不在堆栈上的情况也有可能发生,这是因为内嵌函数能引用更外层外包函数的局部变量:
[cc lang='lua']
function Test(n)
local function foo()
local function inner1()
print(n)
end
local function inner2()
n = n + 10
end
return inner1,inner2
end
return foo
end
t = Test(1979)
f1,f2 = t()
f1() -- 打印1979
f2()
f1() -- 打印1989
g1,g2 = t()
g1() -- 打印1989
g2()
g1() -- 打印1999
f1() -- 打印1999
[/cc]
执行完t = Test(1979)后,Test的局部变量n就“死”了,所以当f1,f2这两个闭包被创建时堆栈上根本未找到n的踪影,这叫他们怎么取得n的值呢?呵呵,不要忘了Test函数的n不仅仅是inner1和inner2的upvalue,同时他也是foo的upvalue。t = Test(1979)之后,t这个闭包一定已把n妥善保存好了,之后f1、f2如果在当前堆栈上未找到n就会自动到他们的外包闭包(姑且这么叫)的 upvalue引用数组中去找,并把找到的引用值拷贝到自己的upvalue引用数组中。仔细观察上述代码,能判定g1和g2和f1和f2共享同一个 upvalue。这是为什么呢?其实,g1和g2和f1和f2都是同一个闭包(t)创建的,所以他们引用的upvalue(n)实际也是同一个变量,而刚才描述的搜索机制则确保了最后他们的upvalue引用都会指向同一个地方。
Lua将函数做为基本类型值并支持词法定界的特性使得语言具有强大的抽象能力。而透彻认识函数、闭包和upvalue将帮助程式员善用这种能力。
转载自:http://hi.baidu.com/happynp/blog/item/b7736a1f7f65b3ffe0fe0b90.html
Why is the first random number after randomseed() not random?
The Lua Wiki Math Library Tutorial page[1] says:
"But beware! The first random number you get is not really 'randomized'
(at least in Windows 2K and OS X)."
I observe this same behavior locally. The first number returned by
math.random() after a call to math.randomseed() is always the same. (See
output below.)
Is this acceptable? Is it by design? Wouldn't it be better if (lacking
any other possible fix) math.randomseed() called math.random() once at
the end to throw away the static value?
I'm not interested in cryptographically-secure randomness, but I'd like
my random to be...well...random!
C:>type randomtest_2.lua
[cc lang='lua']
local theSeed = os.time()
for _=1,10 do
theSeed = theSeed + 1
print('Seeding with'..theSeed )
math.randomseed( theSeed )
for i=1,5 do
print( math.random( 1, 100 ) )
end
end
[/cc]
C:>lua5.1 -v randomtest_2.lua
[cc lang='lua']
Lua 5.1.1 Copyright (C) 1994-2006 Lua.org, PUC-Rio
Seeding with 1174327833
66
84
24
35
30
Seeding with 1174327834
66
17
78
9
62
Seeding with 1174327835
66
50
33
82
93
Seeding with 1174327836
66
83
87
56
25
Seeding with 1174327837
66
15
42
29
56
Seeding with 1174327838
66
48
96
3
88
Seeding with 1174327839
66
81
51
76
19
Seeding with 1174327840
66
14
5
49
51
Seeding with 1174327841
66
47
60
23
82
Seeding with 1174327842
66
79
14
96
14
[/cc]
Reprinted from:http://lua-users.org/lists/lua-l/2007-03/msg00553.html
Do you actually need a better randomseed?
Lua math.random (found a nice randomseed)
I've long been put out about how there didn't seem to be a way to get a decent randomseed in Lua—I mean, the system time return didn't have milliseconds (so in my view, the random function wasn't fully functional). I had searched long and hard for a solution, but to no avail.
So, while trying to figure out how to make a network game with LuaSocket, I randomly came across this solution (it requires LuaSocket, by the way):
[cc lang='lua']
require 'socket'
math.randomseed(socket.gettime()*10000)
print(math.random(100))
[/cc]
If you don't multiply it by 10000, it will convert that time into an integer, cutting off the milliseconds, and thus be no better than the regular os.time().
I tried this out and it works fairly well. It's still not perfect as the following code on my 2Ghz dual core AMD Athlon X-2 processor
[cc lang='lua']
for i=1,20 do
math.randomseed(socket.gettime()*10000)
print(math.random())
end
[/cc]
produced the following result,
[cc lang='bash']
0.16043688597178
0.16043688597178
0.16043688597178
0.51493899734455
0.51493899734455
0.51493899734455
0.51493899734455
0.51493899734455
0.51493899734455
0.87877474393639
0.87877474393639
0.87877474393639
0.87877474393639
0.87877474393639
0.2350731134578
0.2350731134578
0.2350731134578
0.2350731134578
0.2350731134578
0.2350731134578
[/cc]
but it's still a whole lot better, and usable as long as you're not changing the seed faster than my computer can do 3–6 calculations in Lua 5.1 (64-bit). Keep in mind that the random numbers generated from a single seed shouldn't repeat the same number like this. So, the following code should be perfect for 99% of the programs out there requiring a random function (using a twist on the example above):
[cc lang='lua']
math.randomseed(socket.gettime()*10000)
for i=1,20 do
print(math.random())
end
[/cc]
Anyway, I just thought I'd share. Enjoy, and let us know if you find/know a better way.
Note: in the poll up there, don't select Yes if the functionality is great but you just don't want to have to use LuaSocket. It's referring to a better randomseed than the LuaSocket one—sorry for not specifying these things in the poll.
Reprinted from:http://ubuntuforums.org/showthread.php?t=1324986
lua 中判断字符串前缀
一个 lua 的小技巧
在写 lua debugger 的时候,我需要判断一个字符串的前缀是不是 "@" 。
有三个方案:
1. 比较直观的是 string.sub(str,1,1) == "@"
2. 感觉效率比较高的是 string.byte(str) == 64
3. 或者是 string.find(str,"@") == 1
我推荐第三种。(注:在此特定运用环境下。因为用于判定 source 的文件名,大多数情况都是 @ 开头。如果结果为非,则性能较低)
第一方案 string.sub 会在生成子串的时候做一次字符串 hash ,感觉效率会略微低一些。
第二方案效率应该是最好,但是需要记住 @ 的 ascii 码 64 。如果前缀是多个字符也不适用。
转载自:http://blog.codingnow.com/2009/05/lua_string_prefix.html
[原创]解除高耦合提高效能
最近有个项目,接口api负载预计会比较繁重,所以将采用队列的模式来解除这个耦合,因为提交的数据不需要很强的时效性,完全可以用异步的模式来处理。前端与api交互的当然是php,这个是毫无疑问的,不过几年的linux的了解和切身体验,在早期的时候也做过一些比较,用写数据为例,写相同数量的数据,如果把C的读写算作1的话,那么用php来处理将会是20左右,而用python,lua这种虚拟机机制更小的语言来处理,那么将是6左右,再加上php执行是加载入过多的模块,呃,至少我不知道如何去除这些模块,所以选择一种轻载的语言来处理进程交互数据,将是提高整体效率的很好途经,代价也比较小,同样的系统环境,可以处理更大的数据量。
使用者(用户)量会很大,访问的api也会很多很频繁,比如微博,所有的api都会汇总在一个平台处理第三方的api,那么如何减少在应用api处提交时对使用者体验最好,互相作用力最小呢?(互相作用力,这里我的意思是:一个节点出现故障,会成为连锁反应,蝴蝶效应,当时在某上市公司的时候就遇到某个时间段突然上升的压力导致了某一台机器缓慢,最终引发整个机房的相关应用全部处于崩溃状态,全部处于active状态,因为都在等那台故障的机器的返回)答案就是引入高效的提交机制,快连快断,加入有序化管理,队列话,队列服务器也可以采用多台,由上层的proxy服务器来随机提交到某个队列中,然后立即返回给用户成功,随后,队列服务器上的进程(当然有条件的可以另外单独服务器)采用多进程盯某个队列,甚至可以优化成优先盯某个队列,某个队列处理完毕后可以辅助处理其他队列服务器中的数据。这里就不展开联想了,思路很多,然后通过进程服务与第三方的多种应用api交互,最终形成了可以任意扩展的异步消息传递系统。
队列服务系统也很多,简单的有张宴基于libevent和tokyocabinet写的httpsqs,当然还有很多复杂的队列,看具体应用而定了。
2010 LUA源码剖析计划启动
为了丰富创建更加绿色环保的业余生活,哥决定,每周抽一定的时间去膜拜lua的源码并形成每周心得,要向日本动漫的永恒主角们学习,即:打不死的人,欠扁的人,执着的人。
最后哥的口号是:YEAH!!必须哒!!!
Lua学习笔记七——lua也面向对象
lua也面相对象?不错,是的。它有面向对象的操作。看看简单示例:
[cc lang="lua"]CTest = { cnt = 0 }
function CTest:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
function CTest.add(self, v)
self.cnt = self.cnt + v
end
function CTest:pprint()
print("CTest...")
end
c1 = CTest
c1.add(c1, 10)
print(c1.cnt)
c1:add(99)
print(c1.cnt)
c1:pprint()
print("\n")[/cc]
一般用this或者self指向当前对象。python用习惯了,和python保持一致,用self来表示。lua中,可以用冒号语法省略self参数的传递,如上例中 c1:pprint() 等价于 c1.pprint(c1)。
有面向对象的特征,当然少不了继承:
[cc lang="lua"]
DTest = CTest:new()
function DTest:pprint()
print("DTest...")
end
d1 = DTest:new{cnt = 2009}
print(d1.cnt)
d1.pprint()
print("\n")
[/cc]
DTest继承自CTest,重写了pprint方法。
有面向对象的特征,当然少不了封装:
[cc lang="lua"]
function ETest(initCnt)
local self = { cnt = initCnt }
local add = function(v)
self.cnt = self.cnt + v
end
local pprint = function()
print "ETest ... "
end
return {
add = add,
pprint = pprint
}
end
e1 = ETest(0)
e1.pprint()
print(e1.cnt) -- 访问不了 cnt,cnt是私有变量
[/cc]
如果对JavaScript比较了解,一看到上面的封装代码,觉得俨然是JavaScript风格,并且和JavaScript封装的行为几乎一模一样。
转载自:http://blog.csdn.net/hong201/archive/2009/05/09/4164070.aspx
