如何判断一个值在lua的table里

最近在用lua写一个nginx模块时,遇到一个需要判断一个值是否在一个table里的问题,我有一个类似如下的一个table:

local items = { "apple", "orange", "pear", "banana" }

我怎样去判断orange是否在这个table里,在python里我可以使用如下的方法:

if "orange" in items:
    # do something

在lua里如何实现类似的方法呢?

Programming in Lua 中提供了一种方法:

function Set (list)
  local set = {}
  for _, l in ipairs(list) do set[l] = true end
  return set
end

你可以使用一个类似set的结构,具体使用的方法如下:

local items = Set { "apple", "orange", "pear", "banana" }

if items["orange"] then
  -- do something
end

上面的这个方法和下面的这个方法等同:

local items = { apple=true, orange=true, pear=true, banana=true }
if items.apple then
    -- do something
end

这个方法足够简单吧,并且效率上要比遍历这个table要高。

– eof –

博客迁移到tinkerer

在11年时,将我的博客从wordpress+mysql换成了django+sqlite,具体可见 将博客从wordpress迁移到django 这篇文章, 在折腾精神的感召下,在12年底我将博客程序又换掉了,这次换成了一个基于 sphinx 静态博客生成器 tinkerertinkerer 使用 reStructuredText 作为标记语言,可以生成文章的分类,tag,支持评论和代码高亮,文章评论使用 disqus , 高亮代码使用 Pygments

说说为什么使用 tinkerer ,从打算把博客弄成静态站点开始我尝试了很多项目,如 octpressjekyllpelican ,一次偶然的机会在 bitbucket 上发现了 tinkerer ,试用后感觉比较顺手,并且可以使用sphinx的扩展,我比较熟悉 sphinxreStructuredText 的使用,平时就用这两个东西写文档,因此选择了基于 sphinxtinkerer 。我最开始使用的是0.4 beta版还存在一些bug,然后我自己做了一些修改pull给作者,作者很快就接受了我的pull request,并表示感谢,现在1.0版本已经发布,基本上没有比较明显的bug了,只是有一些细节可能不是那么完美,还有一个就是主题很少,目前默认的几款主题,都不是很美观,目前我在移植一款主题。

tinkerer的一些使用经验:

* 自定义博客的侧边栏

这里以创建友情链接的plugin作为例子,复制boilerplate主题目录下recent.html为一个新的文件,如friendslinks.html,然后改成如下这样就可以了:

{#-
    boilerplate/friendslinks.html
    ~~~~~~~~~~~~~~~~~~~~~

    Sidebar list of all tags.

    :copyright: Copyright 2012 by Iñigo Serna
    :license: FreeBSD, see LICENSE file
-#}

<div class="widget">
    <h1>Friends links</h1>
    <ul>
        <li><a href="http://www.qdyongai.cn/?from=jason">龙哥-网站设计</a></li>
        <li><a href="http://www.zipeng.info/?from=jason">子鹏-kun的记事本</a></li>
        <li><a href="http://www.aaronw.me/?from=jason">王炜-我的技术生活</a></li>
        <li><a href="http://cuikai-wh.com/?from=jason">小轰-时光立方</a></li>
    </ul>
</div>

这里要注意的是默认的modern5主题是继承于boilerplate这个主题,因此只要修改boilerplate这个主题就可以了

然后在conf.py中加入这个文件的配置

# Add templates to be rendered in sidebar here
html_sidebars = {
    "**": ["searchbox.html", "categories.html", "recent.html", "friendslinks.html", "weibo.html"]
    }
  • 创建一个makefile,使用过 sphinx 的人应该都知道 sphinx 会生成一个 makefile,这样可以直接使用make html就可以生成文档了,tinker没有提供,那么我们可以自己写一个,让我么操作的更加自动化,如下是我 Makefile 示例,大家可以参照下:
all: build commit update

clean:
             rm -rf blog/html/

build:
             tinker -b

serve:
             cd blog/html/ && python -m SimpleHTTPServer

commit:
             hg commit ./ -m 'add new post'&&hg push
                     @echo "Done..."

update:
             ssh root@jasonwu.me 'cd /home/admin/jasonwu.me/&&hg pull&&hg update'

这个makefile主要实现了生成文档,在本地起一个http服务器来查看生成的文章效果,提交到bitbucket和更新vps上的博客内容等功能,将这些操作完全的自动化,是不是很方便,大家玩的开心。

使用NGINX+UWSGI来部署Django

关于UWSGI的介绍不多说了,想了解的可以自己去搜,uwsgi性能还蛮不错,我们之前使用的fastcgi方式来跑django,前端用F5做负载均衡,用户数增加后服务器的load很高,但换uwsgi服务器的load下降不少,废话不多说,进入正题。 编译安装nginx,用的nginx-0.8.54,目前最新的stable版本

wget http://nginx.org/download/nginx-0.8.54.tar.gz
tar zxvf  nginx-0.8.54.tar.gz
./configure --user=nobody
  --group=nobody
  --prefix=/usr/local/nginx
  --with-http_ssl_module
  --http-log-path=/var/log/nginx/access.log
  --with-http_gzip_static_module
make&&make install

下面来安装uwsgi

wget http://projects.unbit.it/downloads/uwsgi-0.9.6.5.tar.gz
tar zvxf uwsgi-0.9.6.5.tar.gz
cd uwsgi-0.9.6.5
make -f Makefile.Py26
cp uwsgi /usr/sbin/uwsgi    #将uwsgi放到PATH下

下面来说说怎么配置: 新建一个uwsgi.xml的文件放到django的目录下

#cat uwsgi.xml
<uwsgi>

<socket>0.0.0.0:8000</socket>

<listen>204800</listen>

<!-- 开启32个线程 -->
<processes>32</processes>

<max-requests>2048000</max-requests>

<buffer-size>8192</buffer-size>

<!-- 你的配置文件 -->
<module>django_wsgi</module>

<profiler>true</profiler>

<enable-threads>true</enable-threads>

<!-- 限制内存空间256M -->
<limit-as>256</limit-as>

<!-- 使用async模式来运行,这里要注意一下,如果你的app的是no-async-friendly 那就不要用这个模式 -->
<async>10</async>

<disable-logging/>

<daemonize>/home/app01/uwsgi.log</daemonize>

</uwsgi>
#cat django_wsgi.py
import os
import django.core.handlers.wsgi
os.environ['DJANGO_SETTINGS_MODULE'] = 'your settings'
application = django.core.handlers.wsgi.WSGIHandler()

下面是nginx的配置:

server {
        listen   80;
        server_name jasonwu.me;
        access_log /var/log/jasownu.me/access_log;
        location / {
            root   /home/app01/;
            uwsgi_pass 127.0.0.1:8000;
            include        uwsgi_params;
      }
  }

启动服务:

/usr/bin/uwsgi -x /home/app01/uwsgi.xml
/usr/local/nginx/sbin/nginx

这样部署完成了

下面来说说遇到的一个问题,不知道大家有没有遇到, 在我们启动uwsgi后在uwsgi的日志中会出现如下的信息:

– unavailable modifier requested: 1 –
– unavailable modifier requested: 1 –

表现的现象就是启动一段时间没法访问app,在查看uwsgi的源代码中我们找到打印这部份日志的段落,正常情况下应该返回的-1,目前还在查找这个出现这个错误的原因。

参考文档:

unp读书笔记(第六章I/O模型)

在看了unp后才发现自己之前的认识一直都是错误的,把阻塞I/O,非阻塞I/O,同步和异步混为一谈,之前一直觉得异步就是非阻塞io,同步就是阻塞io,主要搞清楚了,五种I/O模型的实现,以及epoll并不是aio,这两个并不是一个东西。

实际上unix有五种I/O模型:

  • 阻塞I/O
  • 非阻塞I/O
  • I/O复用(select和poll)
  • 信号驱动I/O(SIGIO)
  • 异步I/O

一个输入操作一般有两个不同的阶段: 1. 等待数据准备好 2. 从内核到进程拷贝数据 对于一个套接口上的输入操作,第一步一般是等待数据到达网络,当分组到达时,它被拷贝到内核中的某个缓冲区,第二步是将数据从内核缓冲区拷贝到应用缓冲区。

1.阻塞I/O模型

最流行的I/O模型是阻塞I/O模型,缺省时,所有套接口都是阻塞的。

http://farm6.staticflickr.com/5195/7407797190_a48b6dcf80_z.jpg

2. 非阻塞I/O模型

前三次调用recvfrom时仍无数据返回,因此内核立即返回一个EWOULDBLOCK错误。第四次调用recvfrom时,数据已经准备好,被拷贝到应用缓冲区,recvfrom返回成功指示,接着就是我们处理数据。当一个应用进程像这样对一个非阻塞描述字循环调用recvfrom时,我们称此过程为轮询(polling)。应用进程连续不断地查询内核,看看某操作是否准备好,这对cpu时间是极大的浪费,但这种模型只是偶尔才遇到,一般是在只专门提供某种功能的系统中才有。

http://farm6.staticflickr.com/5332/7407811366_60f22d6337_z.jpg

3. I/O复用模型

有了I/O复用,我们就可以调用select或poll,在这两个系统调用中的某一个上阻塞,而不是阻塞于真正的I/O系统调用。如图6.3,我们阻塞于select调用,等待数据报套接口可读。当select返回套接口可读条件时,我们调用recvfrom将数据报拷贝到应用缓冲区中。使用select的好处在于我们可以等待多个描述字准备好。

http://farm6.staticflickr.com/5447/7407852344_49d1a95c98_z.jpg

4. 信号驱动I/O模型

我们也可以用信号,让内核在描述字准备好时,用信号SIGIO通知我们,我们将此方法称为信号驱动I/O,如图6.4 首先我们允许套接口进行信号驱动IO,并通过系统调用sigaction安装一个信号处理程序。此系统调用立即返回,进程继续工作,它是非阻塞的。当数据报准备好被读时,就为该进程生成一个SIGIO信号。我们随即可以在信号处理程序中调用recvfrom来读数据报,并通知主循环数据已准备好被处理。也可以通知主循环,让它来读数据报。无论我们如何处理SIGIO信号,这种模型的好处是当等待数据报到达时,可以不阻塞。主循环可以继续执行,只是等待信号处理程序的通知,或者数据已准备好处理,或者数据报已准备好被读。

http://farm8.staticflickr.com/7258/7407859790_b922c7fedf_z.jpg

5. 异步I/O模型

异步IO是POSIX实时扩展,我们让内核启动操作,并在整个操作完成后(包括将数据从内核拷贝到我们自己的缓冲区)通知我们。这种模型没有广泛使用。这种模型与前一节介绍的信号驱动模型的主要区别在于:信号驱动I/O是由内核通知我们何时可以启动一个I/O操作,而异步I/O模型是由内核通知我们I/O操作何时完成。我们调用函数aio_read(POSIX异步I/O函数以aio_或者lio_开头),给内核传递描述字,缓冲区指针,缓冲区大小(与read相同的三个参数),文件偏移(与lseek类似),并告诉内核当前整个操作完成是如何通知我们。此系统调用立即返回,我们的进程不阻塞于等待I/O操作的完成。在此例子中,我们假设要求内核在操作完成时生成一个信号,此信号直到数据已拷贝到应用缓冲区才生成,这一点是与信号驱动I/O模型不同的。

http://farm8.staticflickr.com/7106/7407898142_64f4033a11_z.jpg

6. 五种不同I/O模型的比较

http://farm8.staticflickr.com/7121/7407921310_b58dfa8cb5_z.jpg

7. 同步I/O与异步I/O

POSIX定义这两个术语如下: 同步I/O操作引起请求进程阻塞,直到I/O操作完成。 异步I/O操作不引起请求进程阻塞。 根据上述定义,我们的前四个模型–阻塞I/O模型,非阻塞I/O模型,I/O复用模型和信号驱动I/O模型都是同步I/O模型,因为真正的I/O操作(recvfrom)阻塞进程,只有异步I/O模型与异步I/O的定义相匹配。

Python : 什么是*args和**kwargs?

def foo(*args, **kwargs):
    print 'args = ', args
    print 'kwargs = ', kwargs
    print '---------------------------------------'
if __name__ == '__main__':
    foo(1,2,3,4)
    foo(a=1,b=2,c=3)
    foo(1,2,3,4, a=1,b=2,c=3)
    foo('a', 1, None, a=1, b='2', c=3)

输出结果如下:

| args = (1, 2, 3, 4)
| kwargs = {}
| ---------------------------------------
| args = ()
| kwargs = {'a': 1, 'c': 3, 'b': 2}
| ---------------------------------------
| args = (1, 2, 3, 4)
| kwargs = {'a': 1, 'c': 3, 'b': 2}
| ---------------------------------------
| args = ('a', 1, None)
| kwargs = {'a': 1, 'c': 3, 'b': '2'}
| ---------------------------------------

可以看到,这两个是python中的可变参数。 *args 表示任何多个无名参数,它是一个tuple; **kwargs 表示关键字参数,它是一个dict。并且同时使用 *args**kwargs 时,必须 *args 参数列要在 **kwargs 前,像foo(a=1, b=‘2’, c=3, a’, 1, None, )这样调用的话,会提示语法错误“SyntaxError: non-keyword arg after keyword arg”。

呵呵,知道 *args**kwargs 是什么了吧。还有一个很漂亮的用法,就是创建字典:

def kw_dict(**kwargs):
    return kwargs
    print kw_dict(a=1,b=2,c=3) == {'a':1, 'b':2, 'c':3}

其实python中就带有dict类,使用dict(a=1,b=2,c=3)即可创建一个字典了。

另:连接两个字典的方法:

第一种:

>>> a={'a':'a','b':'b'}
>>> m=dict(c='c',**a)
>>> m
{'a': 'a', 'c': 'c', 'b': 'b'}
>>>

第二种:

>>> a={'a':'a','b':'b'}
>>> m={'c':'c'}
>>> m.update(a)
>>> m
{'a': 'a', 'c': 'c', 'b': 'b'}