我的微博
页面
-
最新发表
分类
存档
Blogroll
博客日历
2010年九月 一 二 三 四 五 六 日 « 八 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 关于我
梦的开始挣扎于
城市的边缘
心的远方执着在
脚步的瞬间
我的宿命埋藏了
寂寞的永远
关于web服务器的测试
测试名单上包括:
一,webservers:
- Apache/1.3.41
- Apache/2.0.63
- nginx-0.6.32
- cherokee-0.9.4
- lighttpd-1.4.19
二,PHP 加速器
- APC-3.0.19
- eaccelerator-0.9.5.3
- xcache-1.2.0
三,server 配置,比如说 PHP 静态,动态编译,Apache 静态,动态编译,mod_fcgid, mod_fastcgi
四,测试用例
- 小 html:echo.html
- 大 html:phpinfo.html
- 小 php:echo.php time.php
- 大 php:smarty.php
- 重 php:phpinfo.php
五,测试点
- webserver 每秒处理的请求数,Request Per Second,rps,前提是对于每个请求, webserver的响应时间不能够超过容忍时间(5-8s)
- 同时并发连接数,指的是不出错的情况下能同时处理的连接数
- 数据吞吐量,单位时间内能够传输的字节数
- 各种webserver与PHP加速器搭配的稳定性
六,测试方法
- autobench-2.1.2,httperf-0.8.1
- ApacheBench, Version 2.0.41-dev
- 对每个测试用例,尝试并发 10,50,100,500,1000,5000
每次 100,000 个请求
每个并发重复测试 4 次,取rps平均数
七,测试环境:Linux Tencent 2.6.16.54-0.2.3-TENCENT-STATE-OC #1 SMP Wed Jan 16 10:38:28 CST 2008 i686 i686 i386 GNU/Linux
cpu: Intel(R) Xeon(TM) CPU 3.00GHz * 4
mem: 2 GB
八,测试结果:保密。。。
九,测试总结:
- 1. 测试的 php 脚本可能无法真实的代表项目实际使用的php功能 2. 各个webserver的调优配置可能会对测试结果有较大的影响
3. 服务器本身的一些设置可能对测试结果也有影响,如 ulimit, sysctl 配置等
4. 测试用的client端机器在一些测试中可能已经成为了瓶颈
5. nginx 启动前需要单独起fastcgi,比较麻烦,lighttpd,apache都不用
6. 据说 lighttpd 1.4 报告过内存泄漏,在特定的配置情况下
7. 就文档,社区,更新速度等人文因素来说,nginx要比lighttpd做的好一些。公司运维有在使用nginx做7层代理
8. xcache和ea在 php-cgi -m 命令下报 “段错误”(php -m 没有),apc 没有
9. apache 的 mod_fcgid 测试中 error 较多,可能调整配置参数可以解决
10. 。。。
腾讯十周年
十周腾讯,十年在线。
想想我的第一个QQ号码,还是高二(2002年)的时候申请的。那时候,班里流行刷夜,也就是在网吧通宵上网。虽然从高一开始写程序,但我对上网,尤其是在网吧上网并不怎么热衷。到了网吧,也就是这点点,那点点。还记得有一阵子打游戏,挑了一个最简单的《飞鹰行动》,总是鼠标键盘一通乱按,结果还是进了屋就出不来。至于那时候别人帮忙申请的QQ号码,早就忘到爪哇国去了。
高考结束后,忽然想起要跟同学们保持联系了,于是到处问人要QQ——那个时候,很多“牛人”会在网吧的机器上种木马,然后偷来一大堆的好QQ号——小蔡给了我一个,于是,一直用到现在。
大学继续编程,继续写代码,继续做比赛。每天挂这QQ,虽然很多时候不聊天,不说话,甚至不怎么回答别人的话。开着QQ,成了一种习惯,一种心情,一如开着手机,只为等待某一个特定的铃声响起。
从木子版到珊瑚虫版,最后到TM,从来不点击QQ上的广告,从来不买QQ的产品,从来不为QQ花一分钱,但,一直使用它。 进了腾讯以后,同事曾笑我说,如果大家都想你这样,那腾讯就没法给你发工资了。
第一个邮箱是TOM的,却拒绝了TOM的一再offer;从来不用新浪的产品,第一份工作却去了新浪;经常嘲笑那些用QQ空间的老同学,跳槽却偏偏到了QQ空间。世间的事情都难以预料,没有什么不可能——阿迪达斯这么说,李宁这么说,奥巴马也这么说。
深圳纪事
24号晚上8点36分,T107开出北京西站。25号晚上8点22分,停靠深圳罗湖车站。
在高中同学的帮助下,从地铁转公交,终于找到了落脚的南航富豪城酒店。第一感觉是,深圳的交通费真贵:地铁5块,公交上车2块,有的还2块5 。
26号周日,抽空去了一趟东莞塘厦——爸爸妈妈,哥哥嫂嫂,还有小浩洋都在那里,难得一次团圆。
27号到飞亚达大厦腾讯报道。不巧的是,部门秘书mm和主管gg都休假了,折腾到28号,才把大部分的手续办完:电脑能上网,OA能进,RTX能进,Token卡能用。
一楼是招行,二楼是餐厅,楼上还有一个甲骨文,和一堆不知名的小公司。
楼下公交车站是大冲站,往东是白石洲和世界之窗,往西是科技园,以及深圳大学。
酒店没有洗衣机,一堆衣服都还没有洗。
从深秋,回到盛夏。
用C语言扩展Python的功能
Pyton和C分别有着各自的优缺点,用Python开发程序速度快,可靠性高,并且有许多现成模块可供使用,但执行速度相对较慢;C语言则正好相反,其执行速度快,但开发效率低。为了充分利用两种语言各自的优点,比较好的做法是用Python开发整个软件框架,而用C语言实现其关键模块。本文介绍如何利用C语言来扩展Python的功能,并辅以具体的实例讲述如何编写Python的扩展模块。
一、简介
Python是一门功能强大的高级脚本语言,它的强大不仅表现在其自身的功能上,而且还表现在其良好的可扩展性上,正因如此,Python已经开始受到越来越多人的青睐,并且被屡屡成功地应用于各类大型软件系统的开发过程中。
与其它普通脚本语言有所不同,Python程序员可以借助Python语言提供的API,使用C或者C++来对Python进行功能性扩展,从而即可以利用Python方便灵活的语法和功能,又可以获得与C或者C++几乎相同的执行性能。执行速度慢是几乎所有脚本语言都具有的共性,也是倍受人们指责的一个重要因素,Python则通过与C语言的有机结合巧妙地解决了这一问题,从而使脚本语言的应用范围得到了很大扩展。
在用Python开发实际软件系统时,很多时候都需要使用C/C++来对Python进行扩展。最常见的情况是目前已经存在一个用C编写的库,需要在Python语言中使用该库的某些功能,此时就可以借助Python提供的扩展功能来实现。此外,由于Python从本质上讲还是一种脚本语言,某些功能用Python实现可能很难满足实际软件系统对执行效率的要求,此时也可以借助Python提供的扩展功能,将这些关键代码段用C或者C++实现,从而提供程序的执行性能。
本文主要介绍Python提供的C语言扩展接口,以及如何使用这些接口和C/C++语言来对Python进行功能性扩展,并辅以具体的实例讲述如何实现Python的功能扩展。
二、Python的C语言接口
Python是用C语言实现的一种脚本语言,本身具有优良的开放性和可扩展性,并提供了方便灵活的应用程序接口(API),从而使得C/C++程序员能够在各个级别上对Python解释器的功能进行扩展。在使用C/C++对Python进行功能扩展之前,必须首先掌握Python解释所提供的C语言接口。
2.1 Python对象(PyObject)
Python是一门面向对象的脚本语言,所有的对象在Python解释器中都被表示成PyObject,PyObject结构包含Python对象的所有成员指针,并且对Python对象的类型信息和引用计数进行维护。在进行Python的扩展编程时,一旦要在C或者C++中对Python对象进行处理,就意味着要维护一个PyObject结构。
在Python的C语言扩展接口中,大部分函数都有一个或者多个参数为PyObject指针类型,并且返回值也大都为PyObject指针。
2.2 引用计数
为了简化内存管理,Python通过引用计数机制实现了自动的垃圾回收功能,Python中的每个对象都有一个引用计数,用来计数该对象在不同场所分别被引用了多少次。每当引用一次Python对象,相应的引用计数就增1,每当消毁一次Python对象,则相应的引用就减1,只有当引用计数为零时,才真正从内存中删除Python对象。
下面的例子说明了Python解释器如何利用引用计数来对Pyhon对象进行管理:
例1:refcount.py
class refcount:
# etc.
r1 = refcount() # 引用计数为1
r2 = r1 # 引用计数为2
del(r1) # 引用计数为1
del(r2) # 引用计数为0,删除对象
|
在C/C++中处理Python对象时,对引用计数进行正确的维护是一个关键问题,处理不好将很容易产生内存泄漏。Python的C语言接口提供了一些宏来对引用计数进行维护,最常见的是用Py_INCREF()来增加使Python对象的引用计数增1,用Py_DECREF()来使Python对象的引用计数减1。
2.3 数据类型
Python定义了六种数据类型:整型、浮点型、字符串、元组、列表和字典,在使用C语言对Python进行功能扩展时,首先要了解如何在C和Python的数据类型间进行转化。
2.3.1 整型、浮点型和字符串
在Python的C语言扩展中要用到整型、浮点型和字符串这三种数据类型时相对比较简单,只需要知道如何生成和维护它们就可以了。下面的例子给出了如何在C语言中使用Python的这三种数据类型:
例2:typeifs.c
// build an integer
PyObject* pInt = Py_BuildValue("i", 2003);
assert(PyInt_Check(pInt));
int i = PyInt_AsLong(pInt);
Py_DECREF(pInt);
// build a float
PyObject* pFloat = Py_BuildValue("f", 3.14f);
assert(PyFloat_Check(pFloat));
float f = PyFloat_AsDouble(pFloat);
Py_DECREF(pFloat);
// build a string
PyObject* pString = Py_BuildValue("s", "Python");
assert(PyString_Check(pString);
int nLen = PyString_Size(pString);
char* s = PyString_AsString(pString);
Py_DECREF(pString);
|
2.3.2 元组
Python语言中的元组是一个长度固定的数组,当Python解释器调用C语言扩展中的方法时,所有非关键字(non-keyword)参数都以元组方式进行传递。下面的例子示范了如何在C语言中使用Python的元组类型:
例3:typetuple.c
// create the tuple
PyObject* pTuple = PyTuple_New(3);
assert(PyTuple_Check(pTuple));
assert(PyTuple_Size(pTuple) == 3);
// set the item
PyTuple_SetItem(pTuple, 0, Py_BuildValue("i", 2003));
PyTuple_SetItem(pTuple, 1, Py_BuildValue("f", 3.14f));
PyTuple_SetItem(pTuple, 2, Py_BuildValue("s", "Python"));
// parse tuple items
int i;
float f;
char *s;
if (!PyArg_ParseTuple(pTuple, "ifs", &i, &f, &s))
PyErr_SetString(PyExc_TypeError, "invalid parameter");
// cleanup
Py_DECREF(pTuple);
|
2.3.3 列表
Python语言中的列表是一个长度可变的数组,列表比元组更为灵活,使用列表可以对其存储的Python对象进行随机访问。下面的例子示范了如何在C语言中使用Python的列表类型:
例4:typelist.c
// create the list
PyObject* pList = PyList_New(3); // new reference
assert(PyList_Check(pList));
// set some initial values
for(int i = 0; i < 3; ++i)
PyList_SetItem(pList, i, Py_BuildValue("i", i));
// insert an item
PyList_Insert(pList, 2, Py_BuildValue("s", "inserted"));
// append an item
PyList_Append(pList, Py_BuildValue("s", "appended"));
// sort the list
PyList_Sort(pList);
// reverse the list
PyList_Reverse(pList);
// fetch and manipulate a list slice
PyObject* pSlice = PyList_GetSlice(pList, 2, 4); // new reference
for(int j = 0; j < PyList_Size(pSlice); ++j) {
PyObject *pValue = PyList_GetItem(pList, j);
assert(pValue);
}
Py_DECREF(pSlice);
// cleanup
Py_DECREF(pList);
|
2.3.4 字典
Python语言中的字典是一个根据关键字进行访问的数据类型。下面的例子示范了如何在C语言中使用Python的字典类型:
例5:typedic.c
// create the dictionary
PyObject* pDict = PyDict_New(); // new reference
assert(PyDict_Check(pDict));
// add a few named values
PyDict_SetItemString(pDict, "first",
Py_BuildValue("i", 2003));
PyDict_SetItemString(pDict, "second",
Py_BuildValue("f", 3.14f));
// enumerate all named values
PyObject* pKeys = PyDict_Keys(); // new reference
for(int i = 0; i < PyList_Size(pKeys); ++i) {
PyObject *pKey = PyList_GetItem(pKeys, i);
PyObject *pValue = PyDict_GetItem(pDict, pKey);
assert(pValue);
}
Py_DECREF(pKeys);
// remove a named value
PyDict_DelItemString(pDict, "second");
// cleanup
Py_DECREF(pDict);
|
三、Python的C语言扩展
3.1 模块封装
在了解了Python的C语言接口后,就可以利用Python解释器提供的这些接口来编写Python的C语言扩展,假设有如下一个C语言函数:
例6:example.c
int fact(int n)
{
if (n <= 1)
return 1;
else
return n * fact(n - 1);
}
|
该函数的功能是计算某个给定自然数的阶乘,如果想在Python解释器中调用该函数,则应该首先将其实现为Python中的一个模块,这需要编写相应的封装接口,如下所示:
例7: wrap.c
#include <Python.h>
PyObject* wrap_fact(PyObject* self, PyObject* args)
{
int n, result;
if (! PyArg_ParseTuple(args, "i:fact", &n))
return NULL;
result = fact(n);
return Py_BuildValue("i", result);
}
static PyMethodDef exampleMethods[] =
{
{"fact", wrap_fact, METH_VARARGS, "Caculate N!"},
{NULL, NULL}
};
void initexample()
{
PyObject* m;
m = Py_InitModule("example", exampleMethods);
}
|
一个典型的Python扩展模块至少应该包含三个部分:导出函数、方法列表和初始化函数。
3.2 导出函数
要在Python解释器中使用C语言中的某个函数,首先要为其编写相应的导出函数,上述例子中的导出函数为wrap_fact。在Python的C语言扩展中,所有的导出函数都具有相同的函数原型:
PyObject* method(PyObject* self, PyObject* args);
该函数是Python解释器和C函数进行交互的接口,带有两个参数:self和args。参数self只在C函数被实现为内联方法(built-in method)时才被用到,通常该参数的值为空(NULL)。参数args中包含了Python解释器要传递给C函数的所有参数,通常使用Python的C语言扩展接口提供的函数PyArg_ParseTuple()来获得这些参数值。
所有的导出函数都返回一个PyObject指针,如果对应的C函数没有真正的返回值(即返回值类型为void),则应返回一个全局的None对象(Py_None),并将其引用计数增1,如下所示:
PyObject* method(PyObject *self, PyObject *args)
{
Py_INCREF(Py_None);
return Py_None;
}
|
3.3 方法列表
方法列表中给出了所有可以被Python解释器使用的方法,上述例子对应的方法列表为:
static PyMethodDef exampleMethods[] =
{
{"fact", wrap_fact, METH_VARARGS, "Caculate N!"},
{NULL, NULL}
};
|
方法列表中的每项由四个部分组成:方法名、导出函数、参数传递方式和方法描述。方法名是从Python解释器中调用该方法时所使用的名字。参数传递方式则规定了Python向C函数传递参数的具体形式,可选的两种方式是METH_VARARGS和METH_KEYWORDS,其中METH_VARARGS是参数传递的标准形式,它通过Python的元组在Python解释器和C函数之间传递参数,若采用METH_KEYWORD方式,则Python解释器和C函数之间将通过Python的字典类型在两者之间进行参数传递。
3.4 初始化函数
所有的Python扩展模块都必须要有一个初始化函数,以便Python解释器能够对模块进行正确的初始化。Python解释器规定所有的初始化函数的函数名都必须以init开头,并加上模块的名字。对于模块example来说,则相应的初始化函数为:
void initexample()
{
PyObject* m;
m = Py_InitModule("example", exampleMethods);
}
|
当Python解释器需要导入该模块时,将根据该模块的名称查找相应的初始化函数,一旦找到则调用该函数进行相应的初始化工作,初始化函数则通过调用Python的C语言扩展接口所提供的函数Py_InitModule(),来向Python解释器注册该模块中所有可以用到的方法。
3.5 编译链接
要在Python解释器中使用C语言编写的扩展模块,必须将其编译成动态链接库的形式。下面以RedHat Linux 8.0为例,介绍如何将C编写的Python扩展模块编译成动态链接库:
[xiaowp@gary code]$ gcc -fpic -c -I/usr/include/python2.2 \
-I /usr/lib/python2.2/config \
example.c wrapper.c
[xiaowp@gary code]$ gcc -shared -o example.so example.o wrapper.o
|
3.6 引入Python解释器
当生成Python扩展模块的动态链接库后,就可以在Python解释器中使用该扩展模块了,与Python自带的模块一样,扩展模块也是通过import命令引入后再使用的,如下所示:
[xiaowp@gary code]$ python Python 2.2.1 (#1, Aug 30 2002, 12:15:30) [GCC 3.2 20020822 (Red Hat Linux Rawhide 3.2-4)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import example >>> example.fact(4) 24 >>> |
四、结束语
作为一门功能强大的脚本语言,Python将被更加广泛地应用于各个领域。为了克服脚本语言执行速度慢的问题,Python提供了相应的C语言扩展接口,通过将影响执行性能的关键代码用C语言实现,可以很大程度上提高用Python编写的脚本在运行时的速度,从而满足实际需要。
参考资料
- 可以从Python( http://www.python.org)网站着手了解所有关于Python的内容。
- 可以在Python网站上找到正式的Python C/API文档( http://www.python.org/doc/current/api/api.html)。
- 可以在Python网站上找到正式的编写Python扩展模块的文档( http://www.python.org/doc/current/api/api.html)。
离开
终于,要走了。
想走已经很久了。
06年底,从播客回到爱问,开始负责维护爱问视频搜索的时候,还是挺开心的:播客上线了,很多人在看; 爱问视频搜索,也有不少人在用。但渐渐的,跟主管(阎培)的相处变的不那么愉快了。07年五一假前, 主管找我谈话,字里行间透露出不满,好像不愿意兑现最初的承诺让我正式的留在新浪。于是我给主管发了一封email,说明了一下情况,希望她能给我一个准确的答复,如果不能留,那么我需要尽快的另外找工作了。
主管并没有回复我的email。五一假,回学校完成毕业论文。等我再回到公司的时候,似乎一切都没有发生过。只是离开的想法已经在脑海中悄悄的开始发芽了。
到了9月正式签约的时候,签的薪资在最初承诺的数字上打了一个不小的折扣。当时便想着,是否应该离开了。可是当时自己处于弱势,户口,经济压力,另外换工作的诸多不确定性,让自己最终还是选择了认命。
于是想着换部门,希望能换个心情重新开始。10月,终于如愿以偿的换到游戏事业部,开始做新版的新浪支付(前天自己用这个支付了3个CD,从银行返回的结果页面居然是404──那个页面的最初版本还是我写的)。新的部门,新的工作内容,新的主管。只是心情经历却如此的一致:从最开始的希望,到最后的深深的失望。
新的部门是因为新上一个项目,所以急着招人。当我搬过去的时候,还只有主管,绍明,彩虹和我四个人。后来,文利和常川来了,李季来了,钱钱来了。也有人来了又走了。那段时间,在17层的“熊猫馆”里,加班,通宵,一次又一次,推倒重来,一遍又一遍。没有ue,主管自己做,没有ui,我们自己切页面,自己写逻辑,自己写底层,自己搭服务器,从上到下都是自己动手做。
在重来的第三遍的时候,终于无法忍受了,跟主管抹开面子说开了以后,又一次,想离开了。支付上线了,计算机在线,tom 也都谈过了,可是,户口的转正定级还没有做完,不能走。只好,再一次转部门。
认识互动的王老大已经很久了,转过去才发现,果然是一个好领导。 08年4月,从游戏事业部转到互动社区。最开始跟刘博1一起做播客的运维。播客已经被运营的非常负责了,140台机器,Apache,Nginx,Squid,Varnish,MemcacheD,MemcacheDB,眼花缭乱的网络部署,复杂无比的页面拼装,再加上时不时出点故障,不停的提提案,切域名,切内网连接。稍微有点空闲的时候,还得想着新的改造方案。
后来书志来了,播客的机器都转给他来管理了,我开始重拾C语言,开始做CSF(Common Server Framework 通用服务器框架)二次开发。通用排序服务,色情图片检测,SSO(单点登录)的在线系统,以及最后的S3(Sina Simple Storage)的调度Dispatcher模块。
中间搬了好几次座位,同组的同事也来来回回换了好几次。最后离职的时候,请来吃饭的同事,除了同在朱岩这个S3组的,却只有源源,刘博他们了。支付的常川和文利打算单请,原来爱问的人,却大都去了开心网了。(ps,以后可以在开心网上找到我:我的id是 101982, 如需要邀请链接,可以用这个 http://www.kaixin001.com/reg/?uid=101982&usercode=e5766f2d598eabb4823ea4779b30e60d_101982) 。
离职进行的很顺利,档案转成个人存档依然留在海淀人才,户口也依然是海淀人才的集体户口,违约金依照新的劳动法取消了,而新的去处──深圳腾讯,也给我订好了半个月的酒店公寓,等着我过去。
在北京五年零一个月,61个月,1800多天。虽然最后户口留在了这里,可她依然不是我的家。拥挤的交通,混浊的空气,干燥的气候,高昂的房价,一切的一切,都令人望而却步。可这里也有北师大的蛋蛋网,有中关村无数的机会,有众多的好学校,从幼儿园到小学到初中到高中到大学,更别说那低的让人无法相信的高考录取分数线,无论是自己的打拼,还是下一代的成长, 这都是一个很吸引人的城市。
我还会回来的,也许,就在不远的将来。
趣味运动会
2008新浪趣味运动会项目设置及比赛规则
1)托球接力跑(每队男、女各5人)
道具:乒乓球、乒乓球拍
比赛规则:参赛队员成一路纵队站在起跑线后,接力比赛要求每名队员用球拍托球绕过指定障碍将球运回至起点,并将球传递给下一名队员,直至10名队员全部完成比赛,用时最短者为胜。托送距离为折返20米。球必须放在球拍上,托运过程中不得用手触球,交接时可以用手;如球在托送途中掉到地上或发生手触球,选手必须回到起点重新开始。
2)袋鼠跳接力(每队男、女各4人)
道具:布袋
比赛规则:参赛队员成一路纵队站在起跳线后,比赛开始,第一人站在布袋内,手提布袋向前跳出,10米后绕过指定标志物跳回并将布袋交给第二人,依次进行,队员若摔倒必须在原地起来恢复原状再跳,最终以用时最短者为胜。
3)盲人足球射门(男)(男子项目:每队4人)
道具:足球
比赛时,射手佩戴眼罩后,裁判在队员前方不定位置摆放5个足球,射手依靠队友的帮助移动位置并将球射入球门。计算全队4人的总进球数,进球多者为胜。数量相同时进行一对一点球。
4)呼啦圈竞走(女)(女子项目:每队4人)
道具:呼啦圈
比赛规则:接力比赛,腰间边转呼啦圈边走(跑),距离为20米,比赛行进当中不得用手转或扶呼啦圈,如落地,需捡起转动后再继续前进,折返点进行接力。最终以用时最短者为胜。
5)高尔夫推杆(仅限大部主管领导参加,比赛成绩计入本团队总分)
道具:高尔夫球和球杆,阻碍区(档板,每一层档板中间均有一个小孔,即球洞)
参赛队员从指定开球位置开始推杆击球,用最少的杆数使球通过4层障碍,杆数最少者为胜。在比赛过程中,比赛队员不得用手触球,不得打半高球。
6)男女夹球接力(每队男、女各5人)
道具:软式排球
比赛规则:5男5女,分成5个接力小组,男女配对。比赛中两人齐心共同将球运送至下一组队友并交给队友,只能使用躯干部位(除手和手臂)运球最终完成接力,距离为20米,以完成时间计算成绩。比赛开始后除捡球和交接外,手及手臂不得接触球。运送途中如球落地,将球捡起回到落地点继续进行。
7)同舟共济(每队男、女各5人,须1名大部主管领导带队)
道具:5人用大木鞋
比赛规则:参赛队员分成两组,分别站在起跑点和折返点,距离10米。第一组队员站在大木鞋上将脚固定,在起跑线后站好。比赛开始,队员协同动作前进,木板后端到达折返点后,第二组队员上大木鞋返回,以木板后端过线为比赛结束,时间少者为胜。如中途有队员摔倒,在原地整理好继续前进,若5分钟全队仍未完成比赛,则终止比赛,成绩为5分钟。
8)集体跳长绳(每队10人,摇绳2人)
比赛规则:比赛时间为一分三十秒,“预备”时将绳摇起,裁判员“发令”开始后,跳绳运动员方可开始跳绳,无论采取何种动作,只要队员跑入绳中跳跃,长绳过双脚一次,再跑出长绳,就计数一次,十名队员需站队依次跳,中间不停表。每名队员每次只能跳一次,多次无效。两名队员一同跳,只计一次。最终以数量最多者为胜,如出现数量相同,则加赛30秒。
9)投篮大赛(每队3男、2女)
道具:投篮机
比赛规则:比赛时间为3分钟,各队队员依次投篮,每人每次投5个球,以最终进球数多者为胜。如出现平分,加赛1分钟。
10)踏浪而来(每队男、女各5人)
比赛规则:比赛过程中全体队员以列的形式站在“履带”内,双手不断的转动“履带”前进,穿越15米距离,履带通过终点线算完成比赛,以用时最短者为胜。在比赛过程中,队员的脚不能踩地,全队超过三次违例,取消成绩。
11)10人11足(每队男、女各5人)
道具:军用帆布扎带
比赛规则:十人排成一排,相邻的两个人分别把左右脚绑在一起,比赛赛道距离30米,十人全部过线为完成比赛,以用时最短者为胜。比赛期间绳松开或脚分开者成绩取消。
12)勇攀高峰(每队4男、1女)
比赛规则:充气攀岩比赛,参赛队员系好护具后开始攀登,目标将新浪logo贴到指定高度,最终以全队完成时间为总成绩。系护具时间不计入比赛时间。具体规则如有调整,请遵守现场公布最终比赛规则。
13)通关大挑战(每队男、女各5人)
比赛规则:比赛场地上共有10个障碍点,全队每人接力完成一关,一杆进洞完成后全队比赛结束,以最终完成时间计算成绩。接力过程中,每名队员过关后需将小浪传给下一名队员,下一名队员才可以进行挑战。
第一关 掷飞镖(有两镖达到9环以上过关)
第二关 跳山羊(跳过山羊过关)
第三关 羽毛球入筐(扔进3个球过关)
第四关 钻杆(仰身过杆不碰杆过关)
第五关 套企鹅(套中3只过关)
第六关 拼图(正确拼出新浪标志过关)
第七关 吹破气球(吹爆一支气球过关)
第八关 俯卧撑(完成20个标准俯卧撑过关)
第九关 答题(五道题,答对三题过关,答对两道罚5秒,答对一道罚10秒,全错罚15秒)
第十关 一锤定音(蒙上眼睛,原地转3圈,敲击终点铜锣)
14)集体拔河(每队10人、其中女不少于1人)
比赛规则:每队10人,赛前领队会通过抽签进行排序,每一轮次比赛不得换人。两队队员所站区域最前端相距中线2米,以红色标志物先到那方区域内为获胜,如比赛出现僵持,2分钟后红色标志物靠近那方为胜。胜出者晋级下一轮次,运动员比赛中不得穿带钉的运动鞋,不得戴手套。采用一局定胜负制。
注:因以上比赛项目均为趣味类项目,规则上没有固定的标准,如规则细则发生变化,以比赛前现场裁判员通知为准。
转正定级
唐福林 福林雨 博客 http://blog.fulin.org/ 转载请保留以上信息
《高等学校毕业生见习期考核鉴定表》
自我鉴定:
从2007年7月毕业开始,我在新浪网技术中国有限公司进行了实习工作。在实习工作过程中,在公司领导和同事们的热心关怀和指导下,我注意把在学校学到的计算机相关的理论知识对照实际工作,用理论知识加深对实际工作的认识,用实践验证所学的相关理论。简短的实习生活,既紧张,又新奇,收获也很多,学到了很多书本上学不到的知识。通过实习,使我对计算机方面的实践经验有了更深层次的认识。
在这一年的实习中,我遵守公司的规章制度,自觉服从领导在工作中的安排。按时按质的完成了上级交给我的所有工作任务。在这一年中,共参与了爱问视频搜索,新浪播客,新浪支付三个项目,在这三个项目中我担任的角色从普通的打杂人员转变为主要开发人员。在提高自己的计算机水平的同时,与同组成员的交流合作也愈加通畅。
回顾我的实习生活,感触是很深的,收获是很多的。然而,由于我本人本科毕业后未能继续深造,工作时间又较短,存在理论知识宽度和广度都不够,工作经验不足等缺陷,在未来的几年里,我将加倍努力工作,养成良好的工作习惯,虚心向前辈学习,争取创造一个光辉灿烂的明天。
《大专院校毕业生转正定级表》
本人简历:
本人1984年12月出生于湖南永州,中学就读于湖南省重点中学东安县第一中学。经高考考入北京师范大学信息科学学院计算机科学技术系。大学期间,努力学习,获国家二等奖学金一次,凹凸电子奖学金一次;积极参加专业相关的学科竞赛ACM(国际大学生程序设计竞赛),并获2005年ACM北京赛区铜牌;积极参与科研,完成了”京师杯”课外科技学术论文大赛参赛作品《离散数学教学辅助软件设计》和北师大本科生科学研究基金项目《北戴河环志数据库设计与实现》;积极参加各种课外活动,先后参加了北师大”白鸽青年志愿者”社团,北师大”农民之子百年育人”义务支教工程,担任了北京西城区图书馆社区学习中心志愿者教师,以及作为环志志愿者前往北戴河环志站进行环志工作。
本科毕业后进入新浪网技术中国有限公司工作,先后参与了爱问视频搜索,新浪播客,新浪支付三个项目的研发工作,在这三个项目中担任的角色也从普通的打杂人员转变为主要开发人员。当前在新浪互动社区的系统开发部参与新浪简单存储服务的开发工作。
字符串相似度算法( Levenshtein Distance算法)
一个字符串可以通过增加一个字符,删除一个字符,替换一个字符得到另外一个字符串,假设,我们把从字符串A转换成字符串B,前面3种操作所执行的最少次数称为AB相似度。
如:
abc adc 度为 1
ababababa babababab 度为 2
abcd acdb 度为2
字符串相似度算法可以使用 Levenshtein Distance算法(中文翻译:编辑距离算法) 这算法是由俄国科学家Levenshtein提出的。其步骤为:
| Step | Description |
|---|---|
| 1 | Set n to be the length of s. Set m to be the length of t. If n = 0, return m and exit. If m = 0, return n and exit. Construct a matrix containing 0..m rows and 0..n columns. |
| 2 | Initialize the first row to 0..n. Initialize the first column to 0..m. |
| 3 | Examine each character of s (i from 1 to n). |
| 4 | Examine each character of t (j from 1 to m). |
| 5 | If s[i] equals t[j], the cost is 0. If s[i] doesn’t equal t[j], the cost is 1. |
| 6 | Set cell d[i,j] of the matrix equal to the minimum of: a. The cell immediately above plus 1: d[i-1,j] + 1. b. The cell immediately to the left plus 1: d[i,j-1] + 1. c. The cell diagonally above and to the left plus the cost: d[i-1,j-1] + cost. |
| 7 | After the iteration steps (3, 4, 5, 6) are complete, the distance is found in cell d[n,m]. |
Tiny CC
转自 IBM developerWorks 中国 Tiny CC
本 文介绍 GNU/Linux 系统上最小的 C 语言编译器 Tiny C 编译器。Tiny C 编译器不仅仅是一个常规意义上的 C 语言编译器,它还使得用户可以像使用脚本语言一样使用 C 语言进行快捷的脚本编程。我们着重介绍用 C 语言进行脚本程序开发的魅力。这个系列将由三篇文章组成,这是第一篇,介绍;在第二篇中,我们将说明如何用标准 C 语言完成通常用 sed 和 awk 完成的字符串处理的工作;在第三篇中,我们将说明如何在自己的编译器项目中使用 TCC 作为机器代码生成器。
TCC 介绍
在 下文中,我们说 Tiny C 编译器、Tiny CC、或者 TCC 都是指的这个 Fabrice Bellard 发明的 GNU/Linux 环境下最小的 ANSI C 语言编译器。TCC 的主页在文后的参考资料中列出。在 Debian GNU/Linux 系统中,可以方便的用 apt-get install tcc 来从网络上安装 TCC 编译器。TCC 的主页上提供有给 Red Hat 系统上使用的 RPM 软件包。在微软 Windows 环境下,可以使用 Cygwin 的模拟 UNIX 的开发环境来编译和使用 Tiny C 编译器。TCC 是自由软件,软件许可证是 GNU LGPL,注意不是 GPL。
TCC 最有趣的特性是可以用 UNIX 系统上常见的 #!/usr/bin/tcc 的方式来执行 ANSI C 语言写就的源程序,省略掉了在命令行上进行编译和链接的步骤,而可以直接运行 C 语言写就的源程序。这样就能做到像任何一种其它的脚本语言比如 Perl 或者是 Python 一样,显著的加快开发步调。可以像编写 Shell 脚本一样的使用 C 语言,随便想一想都觉得是一件奇妙的事情。但是 TCC 还有一些其它的特性呢!
* TCC 的体积非常小,全部源代码打包压缩以后不到 200 K 字节大小,编译后的 tcc 可执行程序不过 80 K 字节大小。这意味着我们几乎可以在任何场合使用 TCC 提供给我们的编写 C 语言脚本的能力。这其中当然包括硬盘空间十分紧张的环境,比如嵌入式系统和启动软盘等等。
* 在给 TCC 的源程序中可以使用任何在给 GCC 的源程序中可以使用的动态链接库。TCC 不仅支持标准的 ANSI C 语言,而且也支持 ISO C99 标准和一部分来自于 GCC 的对 C 语言所做的扩展。
* TCC 直接生成经过部分优化的 X86 机器代码。并不需要生成任何虚拟机的二进制代码。据 TCC 作者提供的数据,TCC 的编译速度比 GNU C 编译器在不做任何代码优化工作(gcc -O0)的时候都要快。当然啦,要是让 GCC 做代码优化的话,那么编译速度就更加比不上 TCC 喽。
下面我们用几个例子来说明 TCC 带给我们的方便。
TCC 的问候
这里是一个简单的 C 语言的 Hello, world! 程序。我们利用这个经典的问候的机会来对 GCC 和 TCC 做一个简单的比较。
#include <stdio.h>
int main(int argc, char **argv)
{
printf(“Hello, world!\n”);
return 0;
}
在命令行上用 gcc -Wall -O2 -o hello hello.c 编译后,再加以 strip hello 把可执行文件中的调试信息都删掉。在 Debian GNU/Linux 上我们得到一个 2592 字节大小的可执行程序。作为比较,我们可以在命令行上用 tcc -run hello.c 直接运行这个经典的问候程序:
$ tcc -run hello.c
Hello, world!
$
程序达到同样的运行效果,可是所需要的相对应的硬盘 空间却只有 hello.c 这个文本文件所占用的 95 个字节。另一方面,我们也可以在命令行上用 tcc -o hello hello.c 像使用 gcc 一样把 hello.c 编译成 ELF 格式的可执行文件然后再运行。在命令行上使用 strip hello 把调试信息删掉以后,我们在同样的 Debian GNU/Linux 系统上得到了一个 1724 字节大小的可执行文件,和 GCC 得到的 2592 字节相比还是小了不少。
为了充分发挥 TCC 的书写 C 语言脚本程序的能力,我们还可以在 hello.c 这个源文件的第一行上按照 UNIX 编写脚本程序的传统加入:
#!/usr/bin/tcc -run
上面的 /usr/bin/tcc 是 Debian GNU/Linux 系统上 tcc 的安装路径,如果你是自己下载的 tcc 源代码进行编译安装的话,你的系统上的 tcc 的安装路径肯定会有所不同,那么当然需要在这里作相应的改变。加入了这一行以后,我们在命令行上 chmod a+x hello.c 使得 hello.c 变成一个可执行文件。这样我们就可以直接运行 hello.c 这个程序了。就像我们可以在命令行上直接运行 Shell 脚本或者是用 Perl 和 Python 写就的脚本程序一样:
$ cat hello.c
#!/usr/bin/tcc -run
#include <stdio.h>
int main(int argc, char **argv)
{
printf(“Hello, world!\n”);
return 0;
}
$ ./hello.c
Hello, world!
$
在这里看出来,TCC 让我们可以省略掉在用 C 语言编程序的时候麻烦的一遍遍的编译和链接的步骤,这真的是非常方便。
TCC 呀 TCC 呀 TCC
在这一小节,让我们来玩一个小小的多重嵌套 TCC 的游戏。
首 先说明一下 TCC 是怎样把命令行参数传递给应用程序的。在命令行 Shell 上输入 tcc -run program.c 就可以不带参数的运行 program.c 这个程序。如果我们需要从命令行上给 program.c 里面的 main(int argc, char **argv) 函数传递命令行参数的话,我们就需要在命令行上输入 tcc -run program.c arg1 arg2 这样的命令;这样 arg1 和 arg2 就被 tcc 传递给了 program.c 程序中的 main() 函数。了解了这一点之后,我们来开始我们的小小游戏。
首先是直接在命令行 Shell 上运行 tcc -v 以输出 tcc 的版本信息。并做一下系统运行时间的测试评估。这里的 tcc 命令是 Debian GNU/Linux 系统上安装在 /usr/bin 目录下面的 tcc 命令。关于 time 命令的细节,读者朋友们可以参考相应的 Manual Page 页面。
$ time tcc -v
tcc version 0.9.19
real 0m0.019s
user 0m0.001s
sys 0m0.017s
接下来让 tcc 嵌套运行 tcc.c 这个源程序。这是 TCC 的 C 语言写就的源程序的主文件,其中有 main() 函数这个 C 语言的入口函数。文件 tcc.c 位于下载自 TCC 主页的 tcc 压缩软件包之中。相关链接在文后一并列出。把下载的 tcc 压缩软件包解开在相应的目录下面,进入该目录,就可以按照如下所示继续我们的小小游戏了。很显然,程序运行所需要的时间变长了。但是让 tcc 自己运行自己,读者朋友们不觉得很有趣吗?下面我们还可以看到更加有趣的东西呢。
$ time tcc -run tcc.c -v
tcc version 0.9.19
real 0m0.385s
user 0m0.147s
sys 0m0.178s
似乎上面让 tcc 自己运行自己还不够好玩,我们要让这样的嵌套更深入一层。首先说明一下 tcc 的 -B 选项设置 tcc 寻找函数库文件的路径;-I 选项设置 tcc 寻找 C 语言头文件的路径。在 Debian GNU/Linux 系统里面,相关的函数库文件和 C 语言头文件安装在下面的命令中所显示出来的路径位置上。系统安装好了的 tcc 自然可以自动找到这些个位置。但是从源文件运行的 tcc.c 则需要我们来告诉它这些文件的位置在哪里。
$ time tcc -run \
> tcc.c -I/usr/lib/tcc/include -B/usr/lib/tcc -run \
> tcc.c -v
tcc version 0.9.19
real 0m0.793s
user 0m0.463s
sys 0m0.249s
现在我们可以看到这样的嵌套几乎可以无休止的进行下去了。让我们把这个嵌套再深入两层,结束我们这个小小的游戏吧。
$ time tcc -run \
> tcc.c -I/usr/lib/tcc/include -B/usr/lib/tcc -run \
> tcc.c -I/usr/lib/tcc/include -B/usr/lib/tcc -run \
> tcc.c -v
tcc version 0.9.19
real 0m1.427s
user 0m0.844s
sys 0m0.406s
下面再来一层嵌套:
$ time tcc -run \
> tcc.c -I/usr/lib/tcc/include -B/usr/lib/tcc -run \
> tcc.c -I/usr/lib/tcc/include -B/usr/lib/tcc -run \
> tcc.c -I/usr/lib/tcc/include -B/usr/lib/tcc -run \
> tcc.c -v
tcc version 0.9.19
real 0m2.381s
user 0m1.167s
sys 0m0.664s
我想有一些“勤恳认真”的读者朋友们不免要问上一句,上面这个小游戏到底有什么意思呢?我的回答是这样的:上面这个小游戏意在说明小巧的东西是很灵活的。这个游戏一方面可以说明 TCC 的代码质量;另一方面,我相信,也可以说服读者朋友们同意,小巧灵活的东西往往可以有出人意料的精彩表演。
在 Shell 管道中使用 TCC
TCC 提供给我们用 C 语言进行脚本编程的能力,但是要最大限度的发挥出脚本编程的潜力来,我们需要在命令行 Shell 的环境中,让 TCC 的脚本程序和其它的命令行 Shell 工具能够紧密的合作才好。在 UNIX 的命令行 Shell 环境中让若干个工具合作的方式就是通过我们熟知的 Shell 的管道机制。下面我们来看看 TCC 和 Shell 的管道机制如何配合。
TCC 和 Shell 管道的配合有两个方面:一是 TCC 编译器本身如何使用管道;二是用 TCC 编写的 C 语言脚本程序如何使用管道。
我 们先来看 TCC 编译器本身如何使用 Shell 管道。在 GNU/Linux 系统上处理管道输入的常见的办法,是让命令行程序可以处理特殊的减号(-)作为命令行参数。本来需要从某一个文件读取输入数据的命令行程序,在接收到这个减号作为命令行参数以后,就改为从标准输入(stdin)读取数据。这样就可以和 Shell 的管道机制配合起来。但是在当前的 TCC 0.9.19 版本中还不能处理这个减号作为命令行参数。不过我们可以有一个替代的办法,就是利用 GNU/Linux 系统上的 /dev/stdin 设备文件。
下面的测试是在 Debian GNU/Linux 系统上做出的。在 Debian GNU/Linux 系统上 /dev/stdin 其实是一个指向 /dev/fd/0 的符号链接;而后者又是一个指向 /dev/pts/0 的符号链接。如果你的 GNU/Linux 系统上没有 /dev/stdin 的话,你还可以使用 /proc/self/fd/0 来代替。
$ cat hello.c | tcc -run /dev/stdin
Hello, world!
上面的这个 hello.c 还是本文开始的时候列出的那个 hello.c 程序。这里我们看到了 TCC 如何利用 GNU/Linux 上的 /dev/stdin 文件来和 Shell 的管道机制协调运行。我们还是再来看一个嵌套运行 tcc.c 的例子。文件 tcc.c 有将近 300 K 字节大小,用 bzip2 压缩以后就只剩下 50 K 字节多一点点。我们现在又知道了怎样利用 Shell 管道,就可以像下面这样运行 tcc 呢。这样在存储空间比较紧张的情况下,又可以节省不少空间了。
$ bzcat tcc.c.bz2 | tcc -I. -B/usr/lib/tcc -run /dev/stdin -v
tcc version 0.9.19
知道了 TCC 编译器如何支持 Shell 的管道功能,我们就可以方便的为我们的 C 语言脚本程序做各式各样所需要的预处理。这样方便的支持对程序源文件进行预处理的功能,对于我们的 C 语言软件开发是极为方便的。
上面讲了 TCC 编译器本身如何支持 Shell 管道,下面讲用 TCC 编写的 C 语言脚本程序如何支持 Shell 管道。
这个其实是很简单的,只要在你的 C 语言脚本程序中恰到好处地使用标准输入(stdin)和标准输出(stdout)就可以了。我们来看一个简单的例子。
#include <stdio.h>
int main(int argc, char **argv)
{
int c;
while ((c = fgetc(stdin)) != EOF) {
fputc(c, stdout);
fputc(c, stdout);
}
return 0;
}
这个程序很简单,它把从标准输入传递进来的每一个字符都重复一遍,然后再传递到标准输出。我们看一下它的运行效果:
$ echo “a”|tcc -run dup.c
aa
$ echo “a”|tcc -run dup.c|sed -e ‘s/a/b/’
ba
$ echo “a”|tcc -run dup.c|sed -e ‘s/a/b/g’
bb
上面这个例子虽然简单,却提示我们可以用 TCC 来做一些简单的字符串处理。这些字符串处理的工作通常都是用 awk 和 sed 这样的工具来完成的。现在有了 TCC 这个工具,我们也可以用 C 语言来完成了。在本系列的下一篇文章中,我们就来看看这方面的例子。
小结
TCC 的小巧灵活的特性使得我们可以在诸如安装软盘、急救软盘、以及微型 GNU/Linux 系统上使用 C 语言进行脚本程序编程工作。在中小型的 C 语言项目中,在开发阶段使用 TCC 进行工作,可以免去编译和链接的步骤,加快测试的速度。这两点是 TCC 带给我们的主要的好处。
此外,我想读者朋友们也会同意用 C 语言进行脚本程序编程,这实在是一件非常有趣的事情。
感谢
感谢 Fabrice Bellard 给我们带来 TCC 这样一个美妙的工具。此外,作者还要感谢 Fabrice Bellard 和 Damian M Gryski 在 Tinycc-devel 邮件列表上提供给作者的帮助。
参考资料
* Tiny CC 的主页 http://fabrice.bellard.free.fr/tcc/
* Debian 的 tcc 软件包的主页 http://packages.debian.org/unstable/devel/tcc.html
* Cygwin 是一个微软 Windows 环境下的模拟 UNIX 的开发和使用环境,大部分主要的 GNU 工具包都有 Cygwin 下的版本。可以在 Cygwin 环境下使用 TCC。Cygwin 的主页在 http://www.cygwin.com
《未完待续》