Skip to content

Lua学习笔记(二)

28-Jul-10

1.Lua可以对多个变量同时赋值,变量列表和值列表的各个元素用逗号分开。
a, b = 10, 2*x

遇到赋值语句Lua会先计算右边所有的值然后再执行赋值操作。
x, y = y, x
a[i], a[j] = a[j], a[i]

但变量个数和值的个数不一致时,Lua会一直以变量个数为基础采取以下策略
a. 变量个数>值的个数 按变量个数补足nil
b. 变量个数<值的个数 多余的值会被忽略

2.使用local创建一个局部变量,与全局变量不同,局部变量只在被声明的那个代码块内有效。代码块:指一个控制结构内,一个函数体,或者一个chunk(变量被声明的那个文件或者文本串)

应该尽可能的使用局部变量,有两个好处:
A. 笔名命名冲突
B. 访问局部变量的速度比全局变量更快

给block划定一个明确的界限:do..end内的部分。

3. Lua语法要求break和return只能出现在block的结尾一句(也就是说:作为chunk的最后一句,或者在end之前,或者else钱,或者until前)。
有时候为了调试或者其他目的需要在block的中间使用return或者break,可以显示的使用do..end

4. Lua函数可以返回多个结果值

Lua学习笔记(一)

28-Jul-10

一、类型和值
1. Lua是动态类型语言,变量不要类型定义。
Lua中有8个基本类型分别为:nil,boolean,number,string,userdata,function,thread,table。
函数type可以测试给定变量或者值的类型。

2. Nil
Lua中特殊的类型,它只有一个值:nil;一个全局变量没有被赋值以前默认值为nil;给全局变量赋nil可以删除该变量。

3. Lua中所有的值都可以作为条件。在控制结构的条件中除了false和nil为假,其他值都为真。所以Lua认为0和空串都是真。

4. Numbers表示实数,Lua中没有整数

5. 一个string可以只包含一个字母也可以包含一本书,Lua可以高效的处理长字符串,1M的string在Lua中是很常见的。可以使用单引号或者双引号表示字符串。还可以使用[[...]]表示字符串。

6. ..在Lua中是字符串连接符,当在数字后面写..时,必须加上空格以防止被解释错误。

7. 显式将string转成数字可以使用函数tonumber(),如果string不是正确的数字该函数将返回nil。反之,可调用tostring()

8. userdata可以将C数据存放在Lua变量中,userdata在Lua中除了赋值和相等比较外,没有预定义的操作。userdata用来描述应用程序或者使用C实现的库创建的新类型。

二、表达式
1. ==和~=比较两个值,如果两个值类型不同,Lua认为两者不同;nil只和自己相等。

2. 为了避免不一致的结果,火鹤比较数字和字符串,Lua会报错,比如:2 < “15″

3. and 和 or的运算结果不是true和false,而是和它的两个操作数相关
a and b –如果a为false,则返回a,否则返回b
a or b –如果a为true,则返回a,否则返回b
x = x or v
等价于
if not x then
x = v
end
4. not的结果一直返回false或者true

5. 表的构造
构造器是创建和初始化表的表达式。表是Lua特有的功能强大的东西。最简单的构造函数是{},用来创建一个空表。
days = {”Sunday”, “Monday”, “Tuesday”}
“Sunday”初始化为days[1](第一个元素索引为1)

MySQL重设密码

30-Jun-10

UPDATE mysql.user SET Password=PASSWORD(’MyNewPass’) WHERE User=’root’;
FLUSH PRIVILEGES;

FTP: 被动和主动连接

30-Jun-10

FTP协议有两种工作方式:PORT方式和PASV方式,即为主动式和被动式。
PORT(主动)方式的连接过程是:客户端向服务器的FTP端口(默认是21)发送连接请求,服务器接受连接,建立一条命令链路。当需要传送数据时,客户端在命令链路上用PORT命令告诉服务器:“我打开了XXXX端口,你过来连接我”。于是服务器从20端口向客户端的XXXX端口发送连接请求,建立一条数据链路来传送数据。
PASV (被动)方式的连接过程是:客户端向服务器的FTP端口(默认是21)发送连接请求,服务器接受连接,建立一条命令链路。当需要传送数据时,服务器在命令链路上用PASV命令告诉客户端:“我打开了XXXX端口,你过来连接我”。于是客户端向服务器的XXXX端口发送连接请求,建立一条数据链路来传送数据。
概括: 主动模式:服务器向客户端敲门,然后客户端开门
被动模式:客户端向服务器敲门,然后服务器开门 所以,如果你是如果通过代理上网的话,就不能用主动模式,因为服务器敲的是上网代理服务器的门,而不是敲客户端的门 而且有时候,客户端也不是轻易就开门的,因为有防火墙阻挡,除非客户端开放大于1024的高端端口 要用主动模式来下载,请您把下载工具的被动模式(PASV)都不要打勾,用主动模式来下载就OK了,如果在出错,那就被动主动相互转换一下

MySQL Replace INTO

17-Jun-10

MySQL Replace INTO说明

REPLACE的运行与INSERT很相像。只有一点除外,如果表中的一个旧记录与一个用于PRIMARY KEY或一个UNIQUE索引的新记录具有相同的值,则在新记录被插入之前,旧记录被删除。请参见13.2.4节,“INSERT语法”。

注意,除非表有一个PRIMARY KEY或UNIQUE索引,否则,使用一个REPLACE语句没有意义。该语句会与INSERT相同,因为没有索引被用于确定是否新行复制了其它的行。

以下是所用算法的更详细的说明(该算法也用于LOAD DATA…REPLACE):

1. 尝试把新行插入到表中

2. 当因为对于主键或唯一关键字出现重复关键字错误而造成插入失败时:

a. 从表中删除含有重复关键字值的冲突行

b. 再次尝试把新行插入到表中

数据库设计Tool – DbWrench

25-May-10

这周末要去下沙给学生,讲一个选课和课程系统,今天备课中,需要设计一个数据库,画一个diagram,在网上google了一圈,发现还是DbWrench最好。Free,Fast, Easy to use. 因为之前用过,功能及实用性方面都不错,当然功能性跟PowerDesigner是没法比,但对于小型的项目,根本没有必要动用PD这样的大工具,用这个短小精悍的DbWrench就OK了。

首先我们来看下DbWrench官网的介绍:
1. Simple to Learn, Easy to Use
2. Create Entity Relation Diagrams (ERDs)
3. Forward Engineer New Databases
4. Reverse Engineer Existing Databases
5. Synchronize your databases and designs in either direction
6. Advanced SQL Query Editor
7. Cross Platform Support

跨平台,支持Windows, Linux, Mac操作系统及 Microsoft SQL Server, MySQL, PostgreSQL数据库系统

OK,下面上图,来个更直观:(点击图片,查看大图)

官方网站: http://www.dbwrench.com

2010.05.22 Google Doodle

23-May-10

In Japan on May 22, 1980, Pac-Man was released – which is now, although it is May 21st here in USA. To celebrate the 30th anniversary of Pac Man, Google has their first ever playable and interactive logo. Here is a picture of Google.com today:

Google Doodle

Base64编码

22-Mar-10

什么是Base64?
按照RFC2045的定义,Base64被定义为:Base64内容传送编码被设计用来把任意序列的8位字节描述为一种不易被人直接识别的形式。(The Base64 Content-Transfer-Encoding is designed to represent arbitrary sequences of octets in a form that need not be humanly readable.)

Base64编码详解
Base64 编码要求把3个8位字节(3*8=24)转化为4个6位的字节(4*6=24),之后在6位的前面补两个0,形成8位一个字节的形式。
具体转化形式间下图:
字符串”小李”,GBK的中文编码是D0A1 C0EE,转化成字节为
11010000 10100001 11000000 11101110

再把8位转为6位
00110100 00001010 00000111 00000000 00111011 00100000

可以这么考虑:把8位的字节连成一串 11010000101000011100000011101110
然后每次顺序选6个出来之后再把这6二进制数前面再添加两个0,就成了一个新的字节。之后再选出6个来,再添加0,依此类推,直到30个二进制数被选,剩下两个怎么办呢,前面照旧补两个0,后面不够6位的,全部用0补全。

让我们来看看实际结果:
字符串”小李”
11010000 HEX:D0 10100001 HEX:A1 11000000 HEX:C0 11101110 HEX:EE

00110100 00001010 00000111 00000000 00111011 00100000

十进制52 十进制10 十进制7 十进制0 十进制59 十进制32

Base64有其自身的编码表:

The Base64 Alphabet
Value Encoding
0 A
1 B
2 C
3 D
4 E
5 F
6 G
7 H
8 I
9 J
10 K
11 L
12 M
13 N
14 O
15 P
16 Q
17 R
18 S
19 T
20 U
21 V
22 W
23 X
24 Y
25 Z
26 a
27 b
28 c
29 d
30 e
31 f
32 g
33 h
34 i
35 j
36 k
37 l
38 m
39 n
40 o
41 p
42 q
43 r
44 s
45 t
46 u
47 v
48 w
49 x
50 y
51 z
52 0
53 1
54 2
55 3
56 4
57 5
58 6
59 7
60 8
61 9
62 +
63 /
(pad)=

这也是 Base64名称的由来,而Base64编码的结果不是根据算法把编码变为高两位是0而低6为代表数据,而是变为了上表的形式。表中,编码的编号对应的是得出的新字节的十进制值。因此,从表2可以得到对应的Base64编码:

字符串”小李”
11010000 HEX:D0 10100001 HEX:A1 11000000 HEX:C0 11101110 HEX:EE

00110100 00001010 00000111 00000000 00111011 00100000
十进制52 十进制10 十进制7 十进制0 十进制59 十进制32

这样,字符串”小李”经过编码后就成了字符串”0KHA7g”了。
Base64将3个字节转变为4个字节,因此,编码后的代码量(以字节为单位,下同)约比编码前的代码量多了 1/3。之所以说是“约”,是因为如果代码量正好是3的整数倍,那么自然是多了1/3。但如果不是呢?
细心的人可能已经注意到了,在The Base64 Alphabet中的最后一个有一个(pad) =字符。这个字符的目的就是用来处理这个问题的。
当代码量不是3的整数倍时,代码量/3的余数自然就是2或者1。转换的时候,结果不够6位的用0来补上相应的位置,之后再在6位的前面补两个0。转换完空出的结果就用就用“=”来补位。譬如结果上面的例子”小李”,就不够3的整数,所以用0来补整6个数,再在前面加两个0.

这样,最后的缺少的2个字节用=不上,所以”小张”的base64_encode就是”0KHA7g==”。

MySQL数据库性能优化的几个关键参数

17-Mar-10

关键参数一:back_log
要求 MySQL 能有的连接数量。当主要MySQL线程在一个很短时间内得到非常多的连接请求,这就起作用,然后主线程花些时间(尽管很短)检查连接并且启动一个新线程。

back_log 值指出在MySQL暂时停止回答新请求之前的短时间内多少个请求可以被存在堆栈中。只有如果期望在一个短时间内有很多连接,你需要增加它,换句话说,这值 对到来的TCP/IP连接的侦听队列的大小。你的操作系统在这个队列大小上有它自己的限制。 试图设定back_log高于你的操作系统的限制将是无效的。

当你观察你的主机进程列表,发现大量 264084 | unauthenticated user | xxx.xxx.xxx.xxx | NULL | Connect | NULL | login | NULL 的待连接进程时,就要加大 back_log 的值了。默认数值是50,我把它改为500。

关键参数二:interactive_timeout
服务器在关闭它前在一个交互连接上等待行动的秒数。一个交互的客户被定义为对 mysql_real_connect()使用 CLIENT_INTERACTIVE 选项的客户。 默认数值是28800,我把它改为7200。

关键参数三:key_buffer_size
索引块是缓冲的并且被所有的线程共享。key_buffer_size是用于索引块的缓冲区大小,增加它可得到更好处理的索引(对所有读和多重写),到你 能负担得起那样多。如果你使它太大,系统将开始换页并且真的变慢了。默认数值是8388600(8M),我的MySQL主机有2GB内存,所以我把它改为 402649088(400MB)。

关键参数四:max_connections
允许的同时客户的数量。增加该值增加 mysqld 要求的文件描述符的数量。这个数字应该增加,否则,你将经常看到 Too many connections 错误。 默认数值是100,我把它改为1024 。

关键参数五:record_buffer
每个进行一个顺序扫描的线程为其扫描的每张表分配这个大小的一个缓冲区。如果你做很多顺序扫描,你可能想要增加该值。默认数值是 131072(128K),我把它改为16773120 (16M)

关键参数六:sort_buffer
每个需要进行排序的线程分配该大小的一个缓冲区。增加这值加速ORDER BY或GROUP BY操作。默认数值是2097144(2M),我把它改为 16777208 (16M)。

关键参数七:table_cache
为所有线程打开表的数量。增加该值能增加mysqld要求的文件描述符的数量。MySQL对每个唯一打开的表需要2个文件描述符。默认数值是64,我把它改为512。

关键参数八:thread_cache_size
可以复用的保存在中的线程的数量。如果有,新的线程从缓存中取得,当断开连接的时候如果有空间,客户的线置在缓存中。如果有很多新的线程,为了提高性能可 以这个变量值。通过比较 Connections 和 Threads_created 状态的变量,可以看到这个变量的作用。我把它设置为 80。

关键参数九:wait_timeout
服务器在关闭它之前在一个连接上等待行动的秒数。 默认数值是28800,我把它改为7200。

注:参数的调整可以通过修改 /etc/my.cnf 文件并重启 MySQL 实现。

Drupal 缓存基础

17-Mar-10

在Drupal中创建复杂的、动态的内容是很easy的,但需要做出一定的牺牲的。现在很多Web 2.0的特性的加入,使得网站在变得很cool的同时,也坠入了“性能恶梦(performance nightmare)”的深渊中。每一个节点的加载或一个页面的加载,都会引起高负载、大量的数据库访问、复杂的计算和大量的客户端脚本的执行。

一个解决方案是在Drupal的管理界面开启页面缓存。这个可以使匿名用户(即不登录的情况下)访问速度增加,因为Drupal会把每一个要输出的页面预先缓存(请注意!不是缓存成HTML页面,而是把整个页面的HTML内容序列化为字符串,然后存入数据库),这样可以大大的减少数据库的查询次数。但是,这个对于登录的用户是没有任何效果的:因为页面级的缓存是一种”要么全是要么就一点都没有(all-or-nothing)”的缓存方式,它只有在很标准的情况下才有效,并且所有用户看到的视图都是一样的。

不过,早晚有一天你需要挖掘你的代码,找出数据库的查询访问热点(hot spots),然后自己对程序进行缓存。幸运的是(我最喜欢看到Fortunately这个单词),Drupal有一些内建的关于缓存的API和一些指导性的文档,使得我们可以很easy的自定义Drupal程序的缓存。

基础
做优化和缓存的第一条(The first rule)就是:永远不要使消耗时间的操作执行两次!要充分利用第一次执行的结果,并重用它们(Never do something time consuming twice if you can hold onto the results and re-use them.)下面我们看一个简单的示例:

function my_module_function($reset = FALSE) {
  static $my_data;
  if (!isset($my_data) || $reset) {
    // 在些进行复杂的计算,并使用正确的内容生成$my_data变量
  }
  return $my_data;
}

这段代码中最重要的部分,就是这个函数创建了一个静态变量——$my_data.静态变量的好处在于,当其第一次被赋值后,就可以被持续的使用,即使这个函数被重新调用。也就是说,我们先检查这个变量是否被赋值,如果已经有值了,那就不需要重新计算,只需要直接返回其值即可。

这种模式经常在Drupal中使用——其中包括很多关键的函数,如node_load。这个函数在被第一次调用时,根据传入的节点ID,查询数据库得到节点对像,并赋值于一个静态变量;然后如果这个节点再在一个Block中被调用,或被列表中调用,就不会再次查询数据库了。

另一个重要的特性是使用$reset参数。缓存确实很好,但偶尔你也需要确保用户访问的页面所得到的数据是绝对新鲜的(absolute freshest)。这时$reset变量就派上用场了。我们可以在需要更新缓存的时候,将$reset设置为TRUE。

Drpual的缓存函数
你可能注意到,静态变量只能在一个单独的页面生存周期内有效。如果需要更好的性能,我们可以使缓存的数据更持久……

function my_module_function($reset = FALSE) {
  static $my_data;
  if (!isset($my_data) || $reset) {
    if (!$reset && ($cache = cache_get('my_module_data')) && !empty($cache->data)) {
      $my_data = unserialize($cache->data);
    }
    else {
      // 处理复杂计算,生成$my_data变量
      cache_set('my_module_data', 'cache', serialize($my_data));
    }
  }
  return $my_data;
}

这个版本的函数仍然使用静态变量,但是它增加了新的一个层(layer):数据缓存层。Drupal的API提供三个关键的函数你需要了解:cache_get(), cache_set()和cache_clear_all()。接下来让我们看看如何使用它们。

回到上面的函数,在对静态变量做初始检查后,这个函数就会通过一个键来查找Drupal缓存(数据库中的缓存)。如果能够查到,并且$cache->data元素是非空的,函数公反序列化缓存数据,并将其存入$my_data变量中。

如果没有缓存被找到(或如果$reset == TRUE),函数就会实际生成数据。然后它会将其序列化再存入数据库,这样以后就可以在将来被使用了。缓存的键值(key)的命名最好以你自定义模块的名称为前缀,这样便于标识。

最终的结果是什么?一个很聪明很轻便的函数可能节省很多的时间——首先检查内存中是否已有变量存在(静态变量),然后再检查数据库缓存,如果这些都没有那就重新生成。如果你查看很多针对数据库查询的模块的话,会发现很多模块都应用了这种模式。

保持最新

发生了什么呢?如果你缓存的数据过期了,并且需要重新计算呢?默认的情况下,缓存的信息将会一直存在直到某模块执行了cache_clear_all()函数,清空所有的数据。如果你的数据偶尔的被更新,那么当每次你需要做一些更改时你或许可以考虑简单的调用cache_clear_all(‘my_module_data’, ‘cache’)。如果你缓存了很多数据(比如你为一个模块存储了n个缓存,或为每个角色都做了个缓存),那么可以传入第三个参数给cache_clear_all函数,以使其全部清空:

cache_clear_all('my_module', 'cache', TRUE);

上面的函数将清空所有以“my_module”为前缀的键值的缓存。

如果你不需要使你的缓存“时刻保持最新“,但又需要使其“适当的”新鲜(reasonably fresh),你可以给cache_set函数传入一个过期时间。比如:

cache_set('my_module_data', 'cache', serialize($my_data), time() + 360);

最后一个参数是一个UNIX时间戳,用来表示过期时间。最简单的方法是使用time()函数,再加上这个缓存的生存时间(以秒为单位)。过期的缓存会被自动的清除(应该是通过cron函数来实现)。

高级缓存
你可能注意到了cache_set()函数的第二个参数是“cache”——这是Drupal用于存放缓存的默认的数据表的名称。如果你要存储大量的数据在缓存中,你可以设置一个自定义的单独的缓存表,并通过这个参数传递给Drupal。这样可以使缓存更快一些,因为可以与其它的模块的缓存表分开。我们熟悉的Views模块就是使用的这种模式(单独创建缓存数据表),尤其当需要清除所有缓存时,单独的缓存表可以避免删除其它模块的缓存数据。

如果你真的希望充分利用服务器的每一个资源,Drupal还提供了可以使用其它缓存系统的机制。只需要改settings.php的一行代码,你就可以使三个标准函数cache_set(), cache_get(),和cache_clear_all()函数有不同的实现。基于文件的缓存(File-based caching),与memcached集成,或使用其它的缓存系统都成为可能。而且,只要你使用了Drupal的标准的缓存函数(就是上面提到的三个),那么你不需要在你的模块中更改任何代码,就可以实现缓存系统的移植。

一些忠告
过犹不及(Like all good things, it’s possible to overdo it)。有时用缓存是不需要的——如果你只是查找一条数据的话,把它存入缓存数据表就是很愚蠢的行为了。可以使用Devel模块来定位哪些查询降低了加载的性能。它可以高亮一些查询时间较长的查询,以及那些被反复执行的查询。

在其它时间,你使用的数据可能会不适合标准的缓存系统。如果你需要在SQL查询中连接缓存数据,比如,cache_set()将会把数据字符串序列化,有时就会造成麻烦(因为不能直接使用)。在这种情形下,你需要找一个针对你的模块的缓存解决方案。VotingAPI模块维护了一个数据表用于存放每个用户的投票结果,另一个数据表用于存储计算结果(如平均值、总和等),这样可以在SQL查询时,快速的进行连接排序和过滤节点。

最后,一定要记住:缓存不是一个长久的存储方式!因为如果其它的模块调用了cache_clear_all()函数的话,那么所有的缓存数据就都会消失。因此如果你要存放某些只能计算一次的数据的话,还是找个安全点的地方放比较好。

备案/许可证编号为: 浙ICP备09097601号 | 网址专家互链 | 友情链接站