所谓生活就是在你忙着制定其他计划的时候发生的事情。
顺其自然,而不是众里寻他千百度,也不是无中生有。
机会就在我们周围,但被我们的信念和习惯断送。
无心插柳柳成荫的两大障碍:杞人忧天(ego-fear)和“计划”。
每一次让恐惧从脸上消失的经历都会让你获得力量、勇气和信心。你必须做那些你认为自己做不到的事情。
消除杞人忧天、释放偶然性的方法很简单:找出杞人忧天。找到它,识破它,消灭它。
一种感恩的心态。
计划本身毫无价值。计划的过程很有必要。
随机应变,保持开放心态是明智之举。
凡事必须有个“计划”还会导致优柔寡断(paralysis of analysis):我们把所有精力都投入到制定完美计划的过程中去,结果实际上什么也没做。更有效的办法是选定一个哪怕有缺点的计划,在行动中制定计划,然后根据实际需要调整、修订、或改变计划。
日子在不知不觉中过去,再见,2010年,一个我不是很喜欢的年份。
关键字:纠结,肤浅,急躁
1、自身职业发展及定位遇到了瓶颈-》纠结
2、感情没有归宿,不明确,总逃避-》纠结
3、专业技能,只有广度,没有深度-》肤浅
4、纯粹拿来主义,毫无贡献的用着-》肤浅
5、自身用户体验差,做事常带情绪-》急躁
身处在2011的今天,我对这一年还是充满希望的。
希望这是快乐和幸福的一年,成长的一年。
关键字:学习,分享,品牌
1、多读书-》学习
2、广交朋友-》学习,分享
3、一门新的编程语言-》学习
4、分享学到的东西-》分享
5、逐步做出自己的品牌-》品牌
1.直接在http://www.sphinxsearch.com/downloads.html找到最新的windows版本,我这里下的是 Win32 release binaries with MySQL support,下载后解压在D:\sphinx目录下;
2.在D:\sphinx\下新建一个data目录用来存放索引文件,一个log目录方日志文件,复制D:\sphinx\sphinx.conf.in到D:\sphinx\bin\sphinx.conf(注意修改文件名);
3.修改D:\sphinx\bin\sphinx.conf,我这里列出需要修改的几个:
type = mysql # 数据源,我这里是mysql
sql_host = localhost # 数据库服务器
sql_user = root # 数据库用户名
sql_pass = ” # 数据库密码
sql_db = test # 数据库
sql_port = 3306 # 数据库端口
sql_query_pre = SET NAMES utf8 # 去掉此行前面的注释,如果你的数据库是uft8编码的
index test1
{
# 放索引的目录
path = D:/sphinx/data/
# 编码
charset_type = utf-8
# 指定utf-8的编码表
charset_table = 0..9, A..Z->a..z, _, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F
# 简单分词,只支持0和1,如果要搜索中文,请指定为1
ngram_len = 1
# 需要分词的字符,如果要搜索中文,去掉前面的注释
ngram_chars = U+3000..U+2FA1F
}
# index test1stemmed : test1
# {
# path = @CONFDIR@/data/test1stemmed
# morphology = stem_en
# }
# 如果没有分布式索引,注释掉下面的内容
# index dist1
# {
# ‘distributed’ index type MUST be specified
# type = distributed
# local index to be searched
# there can be many local indexes configured
# local = test1
# local = test1stemmed
# remote agent
# multiple remote agents may be specified
# syntax is ‘hostname:port:index1,[index2[,...]]
# agent = localhost:3313:remote1
# agent = localhost:3314:remote2,remote3
# remote agent connection timeout, milliseconds
# optional, default is 1000 ms, ie. 1 sec
# agent_connect_timeout = 1000
# remote agent query timeout, milliseconds
# optional, default is 3000 ms, ie. 3 sec
# agent_query_timeout = 3000
# }
# 搜索服务需要修改的部分
searchd
{
# 日志
log = D:/sphinx/log/searchd.log
# PID file, searchd process ID file name
pid_file = D:/sphinx/log/searchd.pid
# windows下启动searchd服务一定要注释掉这个
# seamless_rotate = 1
}
4.导入测试数据
C:\Program Files\MySQL\MySQL Server 5.0\bin>mysql -uroot test 5.建立索引 D:\sphinx\bin>indexer.exe –all using config file ‘./sphinx.conf’… D:\sphinx\bin> 6.搜索’test’试试 D:\sphinx\bin>search.exe test using config file ‘./sphinx.conf’… displaying matches: words: 都所出来了吧。 6.测试中文搜索 修改test数据库中documents数据表, UPDATE `test`.`documents` SET `title` = ‘测试中文’, `content` = ‘this is my test document number two,应该搜的到吧’ WHERE `documents`.`id` = 2; 重建索引: D:\sphinx\bin>indexer.exe –all 搜索’中文’试试: D:\sphinx\bin>search.exe 中文 using config file ‘./sphinx.conf’… words: 貌似没有搜到,这是因为windows命令行中的编码是gbk,当然搜不出来。我们可以用程序试试,在D:\sphinx\api下新建一个foo.php的文件,注意utf-8编码
require ’sphinxapi.php’; 启动Sphinx searchd服务 D:\sphinx\bin>searchd.exe WARNING: forcing –console mode on Windows 执行PHP查询:
Sphinx 0.9.8-release (r1533)
Copyright (c) 2001-2008, Andrew Aksyonoff
indexing index ‘test1′…
collected 4 docs, 0.0 MB
sorted 0.0 Mhits, 100.0% done
total 4 docs, 193 bytes
total 0.101 sec, 1916.30 bytes/sec, 39.72 docs/sec
Sphinx 0.9.8-release (r1533)
Copyright (c) 2001-2008, Andrew Aksyonoff
index ‘test1′: query ‘test ‘: returned 3 matches of 3 total in 0.000 sec
1. document=1, weight=2, group_id=1, date_added=Wed Nov 26 14:58:59 2008
id=1
group_id=1
group_id2=5
date_added=2008-11-26 14:58:59
title=test one
content=this is my test document number one. also checking search within
phrases.
2. document=2, weight=2, group_id=1, date_added=Wed Nov 26 14:58:59 2008
id=2
group_id=1
group_id2=6
date_added=2008-11-26 14:58:59
title=test two
content=this is my test document number two
3. document=4, weight=1, group_id=2, date_added=Wed Nov 26 14:58:59 2008
id=4
group_id=2
group_id2=8
date_added=2008-11-26 14:58:59
title=doc number four
content=this is to test groups
1. ‘test’: 3 documents, 5 hits
D:\sphinx\bin>
Sphinx 0.9.8-release (r1533)
Copyright (c) 2001-2008, Andrew Aksyonoff
index ‘test1′: query ‘中文 ‘: returned 0 matches of 0 total in 0.000 sec
D:\sphinx\bin>
$s = new SphinxClient();
$s->SetServer(’localhost’,3312);
$result = $s->Query(’中文’);
var_dump($result);
?>
Sphinx 0.9.8-release (r1533)
Copyright (c) 2001-2008, Andrew Aksyonoff
using config file ‘./sphinx.conf’…
creating server socket on 0.0.0.0:3312
accepting connections
php d:/sphinx/api/foo.php
1)登录管理自己的GAE https://appengine.google.com
2)找到并点击 “Application Settings”
3)看到“Domain Setup”下面有一行字和一个“Add Domain”按钮,
这行字的内容是:
Want to host your application on another domain? Google App Engine uses Google Apps to manage domains. Learn more
先别点击按钮,先点“Google Apps”,弹出一个窗口,在窗口找到“标准”或“Standard Edition”字样,点击它,
如果找不到可直接点击这个链接http://www.google.com/apps/intl/en/group/index.html
4)点“开始使用”或“get started”按钮,接下来就按提示操作即可,注意以下两点:
A:管理员:我拥有或控制此域名,如 yourdomain.com
B:所在地区选中国香港
5)申请后google要验证你所申请时用的域名,看看是不是你自己的,在管理界面上找到“验证域名所有权”,并点击它,google提供两种验证方式,设置域名的CNAME或上传一个html文件到域名空间里,建议选择设置CNAME,这时google会给你一个字符窜如“googlefffffwasdf8a1cb73c”之类,让你增加该CNAME,并指向google.com,添加后先点击(如:googlefffffwasdf8a1cb73c.yourdomain.com),如果看到能转到google.com 主页,说明解析生效了,那就点“验证”,google会提示在48小时内会自动验证,你可以再次点击“验证域名所有权”,重复上面的步骤,我都是通过这样多点几次,直到不再显示要你验证的提示。如果顺利这一步就完成了。
6)回到GAE控制面板,现在可以点击步骤3里的“Add Domain”按钮,输入你的域名yourdomain.com,这时会转到刚才你申请的“Google Apps”页面,添加新域名输入 “www(或其它)”.yourdomain.com。接下来要到你域名的控制面板,添加CNAME,即你刚才所填的“www(或其它)”,让它指向ghs.google.com,注意:指向官方的ghs.google.com 时只有在国外能打开,要想国内能正常访问还得找山寨的ghs,如http://www.you8g.com/ 刚才去看了:当前剩余域名名额 0/3000 没有名额了。(补充:这个网站还会新加的,一用完就会增加名额,所以说总是有名额的。7.14显示“877/4000”,很期待他们的服务越来越稳定。)
如果第6步顺利完成了绑定域名就完成了,验证方法,用代理打开你绑定的域名,如果能打开就绑定正常了。
1.什么是Go语言
Go语言是Google推出的新的一个致力于系统级的编程语言。很多人说它是 C + Python,既有c的灵活高效,又有Python的简单易用,它的原则是 Simple && Fast。它的语法规则很简单。其官方网站上有一个《三天学会Go语言》的教程,包括三部分:基本结构,面向对象,并发。一个周末的时间就差不多可以掌握其基本面貌。相对来说,第三部分“并发”似乎难接受一些。但是如果你对多线程,同步,消息队列这些东西很有经验的话,对它的概念也会容易理解。
2.Go语言的面向对象
Go语言在C语言语法的基础上,以最简洁的形式加入了面向对象。
关于继承:Go语言没有继承。但是它支持嵌入,这个有点类似于其它语言的mixin,可以用来模拟继承。
关于多态:Go 语言的最大特点是它的接口定义。所谓“接口”,就是一组方法的集合。任何一个类只要实现了一个接口的所有方法,则是该接口的实现者,不需要显式声明实现该接口。所以一个没有任何方法的空接口可以代表任何类型。
3.Go语言的并发
Go语言提出一个新的概念—Go例程,有点类似于线程,但是更加轻量,更省资源。Go例程之间的通信方式 ——信道,这是GO 语言的核心概念,有点类似于UNIX的Pipe。在Go语言中,不需要接触线程,锁这些低阶概念。
4.Go语言可以用来做什么
Go语言目前最强的是它的网络功能。它的package中已经实现了最常见的网络协议和编码处理。Go的官方网站使用的就是Go语言,实际上它就是Go的文档系统godoc。
还没有官方对数据库支持,不过因为通过某种办法可以在Go语言中直接调用C函数,所以很容易的实现对MYSQL 或者 Sqlite 这些数据库的支持。
至于GUI,这估计目前还不在设计者的考虑范围之内,因为他们连Windows都不舍得支持。不过可以通过它的http包和template包等等,已经构成了一个WEB框架,可以用来实现WEB GUI的开发,使用Go写一个带有路径分派的Http服务器也就几行代码的事。
作为自由软件的旗舰项目,Richard Stallman 在十多年前刚开始写作 GCC 的时候,还只是把它当作仅仅一个 C 程序语言的编译器;GCC 的意思也只是 GNU C Compiler 而已。经过了这么多年的发展,GCC 已经不仅仅能支持 C 语言;它现在还支持 Ada 语言、C++ 语言、Java 语言、Objective C 语言、Pascal 语言、COBOL语言,以及支持函数式编程和逻辑编程的 Mercury 语言,等等。而 GCC 也不再单只是 GNU C 语言编译器的意思了,而是变成了 GNU Compiler Collection 也即是 GNU 编译器家族的意思了。另一方面,说到 GCC 对于操作系统平台及硬件平台支持,概括起来就是一句话:无所不在。
1 程序编译过程
GCC是CUI(命令行交互界面)程序,这让许多从Windows走出来 Guier们感到恐惧。实际上它也有许多前端窗口界面,Windows下有Dev C++,Linux下譬如KDevelopment,但既然选择了GCC还是将CUL进行到底吧,没有难与不难的问题,只有做与不做的问题!
下面基于一个具体而微的程序,讨论GCC的使用。示例程序如下:
//test.c
#include <stdio.h>
int main(void)
{
printf(“Hello World!\n”);
return 0;
}
这个程序,一步到位的编译指令是:
gcc test.c -o test
输出的可执行文件名为test,Windows用户可能会感到奇怪,可执行文件明怎么没有.exe扩展名呢?Linux系统中,文件类型并非以扩展名识别的!
实质上,上述编译过程是分为四个阶段进行的,即预处理(也称预编译,Preprocessing)、编译(Compilation)、汇编 (Assembly)和连接(Linking)。
1.1 预处理
运行预处理命令:
gcc -E test.c -o test.i 或 gcc -E test.c
可以输出test.i文件中存放着test.c经预处理之后的代码。打开test.i文件,看一看,就明白了。后面那条指令,是直接在命令行窗口中输出预处理后的代码,而不是以文件作为输出设备。gcc的-E选项,可以让编译器在预处理后停止,并输出预处理结果。在本例中,预处理结果就是将 stdio.h 文件中的内容插入到test.c中了。
gcc的-o选项,用于输出处理结果到文件中。
1.2 编译为汇编代码
预处理之后,可直接对生成的test.i文件编译,生成汇编代码:
gcc -S test.i -o test.s
gcc的-S选项,表示在程序编译期间,在生成汇编代码后,停止,-o输出汇编代码文件。
生成的汇编代码如下:
.file “test.c”
.section .rodata
.align 4
.LC0:
.string “Hello World,Linux programming!”
.text
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $4, %esp
movl $.LC0, (%esp)
call puts
movl $0, %eax
addl $4, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.ident “GCC: (GNU) 4.1.0 20060304 (Red Hat 4.1.0-3)”
.section .note.GNU-stack,”",@progbits
1.3 汇编(Assembly)
如果你学过汇编语言,那么你就该知道程序编译到了这个地步,应当使用汇编器,将汇编语言翻译为机器代码了。这一步尤其重要,因为它决定了你生成的程序,能够运行在哪种机器上。gcc使用的汇编器是gas。
在Intel IA-32平台上,还有一些常用的汇编器有:
* 微软的MASM,这是Intel平台上所有汇编器的鼻祖了,它现在已不是微软的独立产品,只是与Visual Studio捆绑在一起。但微软允许其他组织免费分发MASM 6.0。
* NASM,最初是为UNIX环境开发的商业汇编器,最近成为开源的了,可生成UNIX、MS-DOS和32位Windows格式的可执行文件。
* HLA(high level assembler)是Randall Hyde教授创建的,可以在DOS、Windows和Linux操作系统上生成Intel指令码。但HLA设计的主要目的是向初级程序员讲授汇编语言,学院气太浓,不够实用。
与这些汇编器相比,gas可以在不同处理器平台上工作,通常它可以自动检测底层硬件平台并生成适合该平台的正确机器指令码。gas另一个特性是能够创建不同于程序设计所在平台的指令码,譬如我在Intel计算机上工作,但可以为MIPS计算机写程序。
对于上一小节中生成的汇编代码文件test.s,gas汇编器负责将其编译为目标文件,如下:
gcc -c test.s -o test.o
1.4 连接
gcc连接器是gas提供的,负责将程序的目标文件与所需的所有附加的目标文件连接起来,最终生成可执行文件。附加的目标文件包括静态连接库和动态连接库。
对于上一小节中生成的test.o,将其与C标准输入输出库进行连接,最终生成程序test:
gcc test.o -o test
在命令行窗口中,运行test这个小程序,让它说HelloWorld吧!
2、多个程序文件的编译
通常整个程序是由多个源文件组成的,相应地也就形成了多个编译单元,使用GCC能够很好地管理这些编译单元。假设有一个由test1.c和 test2.c两个源文件组成的程序,为了对它们进行编译,并最终生成可执行程序test,可以使用下面这条命令:
# gcc test1.c test2.c -o test
如果同时处理的文件不止一个,GCC仍然会按照预处理、编译和链接的过程依次进行。如果深究起来,上面这条命令大致相当于依次执行如下三条命令:
# gcc -c test1.c -o test1.o
# gcc -c test2.c -o test2.o
# gcc test1.o test2.o -o test
需要打这么多编译指令,看着都累,许多Guier们又要抱怨了。的确如此,如果单单使用GCC来编译你的程序,一千个程序源文件的项目编译至少要在命令行窗口中敲1k次文件名,才能完成一次编译。如果代码有了改动,重新编译,需要再原样输入一次编译指令。再技术高超的Cler也会累死的,但是很奇怪,那些Cler们至今依然活的很生龙活虎,这得益于GNU Make工具,详情见Make基础一节。
3、检错
GCC包含完整的出错检查和警告提示功能,可以帮助程序员写出更为标准、健壮的代码。如下面的代码:
//illcode.c
#include <stdio.h>
void main(void)
{
long long int var = 1;
printf(“It is not standard C code!\n”);
printf(“long long int var=%d”,var);
}
这种代码,可能在老的C语言课本里能够见到,但它是不符合ANSI/ISO C语言标准的。我让同学在Visual Stdio .net 2003上编译了一下,没检测出什么问题来。下面看看GCC可不可以:
gcc -pedantic illcode.c -o illcode
输出结果:
illcode.c: 在函数 ‘main’ 中:
illcode.c:5: 警告:ISO C90 不支持 ‘long long’
illcode.c:4: 警告:‘main’ 的返回类型不是 ‘int’
-pedantic编译选项并不能保证被编译程序与ANSI/ISO C标准的完全兼容,它仅仅只能用来帮助Linux程序员离这个目标越来越近。或者换句话说,-pedantic选项能够帮助程序员发现一些不符合 ANSI/ISO C标准的代码,但不是全部,事实上只有ANSI/ISO C语言标准中要求进行编译器诊断的那些情况,才有可能被GCC发现并提出警告。
如果采用默认的编译,即:gcc -pedantic illcode.c -o illcode。输出:
test.c: 在函数 ‘main’ 中:
test.c:4: 警告:‘main’ 的返回类型不是 ‘int’
上面的示例中,long long int是GNU C的扩展类型,表示64位整型数,这种类型没有纳入C/C++标准中,可见GCC默认的编译指令,无法完全检测出不符合标准C/C++的代码,但要比 Visual Stdio .net 2003一声都不吭要好一些。如果使用-pedantic选项,GCC就可以基本上按照标准C/C++进行代码检测了,不要挑剔什么,迄今为止没有任何一款编译器完全支持标准C/C++的。
除了-pedantic之外,GCC还有一些其它编译选项也能够产生有用的警告信息。这些选项大多以-W开头,其中最有价值的当数-Wall 了,使用它能够使GCC产生尽可能多的警告信息。
GCC给出的警告信息虽然从严格意义上说不能算作错误,但却很可能成为错误的栖身之所。一个优秀的Linux程序员应该尽量避免产生警告信息,使自己的代码始终保持标准、健壮的特性。所以将警告信息当成编码错误来对待,是一种值得赞扬的行为!所以,在编译程序时带上-Werror选项,那么 GCC会在所有产生警告的地方停止编译,迫使程序员对自己的代码进行修改,如下:
gcc -Werror test.c -o test
输出:
cc1: warnings being treated as errors
test.c: 在函数 ‘main’ 中:
test.c:4: 警告:‘main’ 的返回类型不是 ‘int’
4、库文件连接
人家已经发明了轮子,而且物美价廉,那么我们就实在没有必要浪费生命再去发明同样的轮子!开发软件时,完全不使用第三方函数库的情况是比较少见的,通常来讲都需要借助许多函数库的支持才能够完成相应的功能。从程序员的角度看,函数库实际上就是一些头文件(.h)和库文件(so、或lib、 dll)的集合。虽然Linux下的大多数函数都默认将头文件放到/usr/include/目录下,而库文件则放到/usr/lib/目录下;Windows所使用的库文件主要放在Visual Stido的目录下的include和lib,以及系统文件夹下。但也有的时候,我们要用的库不再这些目录下,所以GCC在编译时必须用自己的办法来查找所需要的头文件和库文件。
GCC采用搜索目录的办法来查找所需要的文件,-I选项可以向GCC的头文件搜索路径中添加新的目录。例如,如果在 /home/lyanry/include/目录下有编译时所需要的头文件,为了让GCC能够顺利地找到它们,就可以使用-I选项:
# gcc test.c -I /home/lyanry/include -o test
同样,如果使用了不在标准位置的库文件,那么可以通过-L选项向GCC的库文件搜索路径中添加新的目录。例如,如果在 /home/lyanry/lib/目录下有链接时所需要的库文件libtest.so,为了让GCC能够顺利地找到它,可以使用下面的命令:
# gcc test.c -L /home/lyanry/lib -ltest -o test
上面这条命令中,值得好好解释一下的是-l选项,它指示GCC去连接库文件libfoo.so。Linux下的库文件在命名时有一个约定,那就是应该以 lib三个字母开头,由于所有的库文件都遵循了同样的规范,因此在用-l选项指定链接的库文件名时可以省去lib三个字母,也就是说GCC在对-lfoo 进行处理时,会自动去链接名为libfoo.so的文件。(注:至于在Windows下该怎样连接库文件,未做尝试,以后再谈)
Linux下的库文件分为两大类分别是动态链接库(通常以.so结尾)和静态链接库(通常以.a结尾),二者的区别仅在于程序执行时所需的代码是在运行时动态加载的,还是在编译时静态加载的。动态加载,意味着内存中仅存在一份库代码,所调用的函数只是在调用程序中存在一个映像。而静态加载,意味着将库中所调用的函数代码复制到调用程序中。如果库中存在同名的静态库和动态库,则在默认情况下, GCC在链接时优先使用动态链接库,只有当动态链接库不存在时才考虑使用静态链接库,如果需要的话可以在编译时加上-static选项,强制使用静态链接库。例如,如果在 /home/xiaowp/lib/目录下有链接时所需要的库文件libtest.so和libtest.a,为了让GCC在链接时只用到静态链接库,可以使用下面的命令:
# gcc test.c -L /home/xiaowp/lib -static -ltest -o test
5、优化
代码优化指的是编译器通过分析源代码,找出其中尚未达到最优的部分,然后对其重新进行组合,目的是改善程序的执行性能。GCC 提供的代码优化功能非常强大,它通过编译选项-On来控制优化代码的生成,其中n是一个代表优化级别的整数。对于不同版本的GCC来讲,n的取值范围及其对应的优化效果可能并不完全相同,比较典型的范围是从0变化到2或3。
编译时使用选项-O可以告诉GCC同时减小代码的长度和执行时间,其效果等价于-O1。在这一级别上能够进行的优化类型虽然取决于目标处理器,但一般都会包括线程跳转(Thread Jump)和延迟退栈(Deferred Stack Pops)两种优化。选项-O2告诉GCC除了完成所有-O1级别的优化之外,同时还要进行一些额外的调整工作,如处理器指令调度等。选项-O3则除了完成所有-O2级别的优化之外,还包括循环展开和其它一些与处理器特性相关的优化工作。通常来说,数字越大优化的等级越高,同时也就意味着程序的运行速度越快。许多Linux程序员都喜欢使用-O2选项,因为它在优化长度、编译时间和代码大小之间,取得了一个比较理想的平衡点。
下面通过具体实例来感受一下GCC的代码优化功能,所用程序如下:
//testOpt.c
#include <stdio.h>
int main(void)
{
double counter;
double result;
double temp;
for (counter = 0; counter != 2000.0 * 2000.0 * 2000.0 / 20.0 + 2000; counter += (5 – 1) / 4)
{
temp = counter / 1979;
result = counter;
}
printf(“Result is %lf\n”, result);
return 0;
}
首先不加任何优化选项进行编译:
gcc -Wall testOpt.c -o testOpt
借助Linux提供的time命令,可以大致统计出该程序在运行时所需要的时间:
$time ./testOpt
Result is 400001999.000000
real 0m7.759s
user 0m7.444s
sys 0m0.008s
接下去使用-O1优化选项来对代码进行优化处理:
gcc -Wall -O testOpt.c -o testOpt
测试运行时间:
$time ./testOPt
Result is 400001999.000000
real 0m2.445s
user 0m2.436s
sys 0m0.000s
接下去使用-O2优化选项来对代码进行优化处理:
gcc -Wall -O2 testOpt.c -o testOpt
测试运行时间:
$time ./testOPt
Result is 400001999.000000
real 0m2.338s
user 0m2.320s
sys 0m0.004s
尽管GCC的代码优化功能非常强大,但作为一名优秀的Linux程序员,首先还是要力求能够手工编写出高质量的代码。如果编写的代码简短,并且逻辑性强,编译器就不会做更多的工作,甚至根本用不着优化。特别在以下一些场合中应该避免使用优化:
1. 程序开发的时候优化等级越高,消耗在编译上的时间就越长,因此在开发的时候最好不要使用优化选项,只有到软件发行或开发结束的时候,才考虑对最终生成的代码进行优化。
2. 资源受限的时候一些优化选项会增加可执行代码的体积,如果程序在运行时能够申请到的内存资源非常紧张(如一些实时嵌入式设备),那就不要对代码进行优化,因为由这带来的负面影响可能会产生非常严重的后果。
3. 跟踪调试的时候对代码进行优化,容易导致某些代码可能会被删除或改写,或者为了取得更佳的性能而进行重组,从而使跟踪和调试变得异常困难。
6、程序性能分析
GCC支持的其它调试选项还包括-p和-pg,它们会将剖析(Profiling)信息加入到最终生成的二进制代码中。剖析信息即包含了更为详细的调试信息(只是我这么觉得,由下面的例子可以证实),也对于找出程序的性能瓶颈很有帮助,是协助Linux程序员开发出高性能程序的有力工具。在编译时加入 -p选项会在生成的代码中加入通用剖析工具(Prof)能够识别的统计信息,而 -pg选项则生成只有GNU剖析工具(Gprof)才能识别的统计信息。下面我们还是以crash.c程序的编译和调试,来看看使用-p选项对程序调试的好处吧。
编译:
gcc -Wall -g -p crash.c -o crash
调试:
[lyanry@lyanry crash]$ gdb -q crash
Using host libthread_db library “/lib/libthread_db.so.1″.
(gdb) run
Starting program: /home/lyanry/program/c++/crash/crash
Reading symbols from shared object read from target memory…done.
Loaded system supplied DSO at 0×909000
Input an integer:11
Program received signal SIGSEGV, Segmentation fault.
0×00971667 in _IO_vfscanf_internal () from /lib/libc.so.6
(gdb) backtrace
#0 0×00971667 in _IO_vfscanf_internal () from /lib/libc.so.6
#1 0×00979337 in scanf () from /lib/libc.so.6
#2 0×08048520 in main () at crash.c:8
现在,可以从GDB输出结果中看到带有出错代码行号的backtrace结果了,即#2 0×08048520 in main () at crash.c:8,使用frame指令,查看出错代码,结果如下:
(gdb) frame 2
#2 0×08048520 in main () at crash.c:8
8 scanf(“%d”, input);
现在有点清晰地知道问题发生在哪了吧!
下面,来测试-p或-pg选项用于分析程序的性能瓶颈,结合前面的叙述,看一下man手册上对-p和-pg选项的详细说明:
-p Generate extra code to write profile information suitable for the
analysis program prof. You must use this option when compiling the
source files you want data about, and you must also use it when
linking.
-pg Generate extra code to write profile information suitable for the
analysis program gprof. You must use this option when compiling
the source files you want data about, and you must also use it when
linking.
说明中所提及的prof和gprof,都是程序性能剖析工具,prof是通用的,gprof是GNU开发的。以例程profile.c来测试 gprof,在编译程序时要添加-gp选项。要注意,这个选项只是在连接期间产生作用的。profile.c代码清单如下:
//profile.c
#include <stdio.h>
void function1()
{
int i=0,j;
for(j=0;j<100000;j++)
i+=j;
}
void function2()
{
int i,j;
function1();
for(j=0;j<200000;j++)
i=j;
}
int main(void)
{
int i,j;
for(i=0;i<100;i++)
function1();
for(j=0;i<50000;i++)
function2();
return 0;
}
编译:
gcc -Wall -pg profile.c -o profile
运行profile程序,会在当前目录中生成一个gmon.out文件,下面可以使用gprof工具对profile程序进行剖析了:
gprof profile >gprof.txt
上面指令执行时,gprof会自动使用gmon.out文件,将输出结果重定向到gprof.txt文件中。如果想知道gmon.out是什么,还是看看man手册里的描述吧:
“Gprof” reads the given object file (the default is “a.out”) and establishes the relation between its symbol table and the call graph profile from gmon.out.
好了,现在要做的事情,就是在当前目录下打开gprof.txt,看看了,文件中,我们感兴趣的内容通常有两处:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls us/call us/call name
66.92 24.44 24.44 49900 489.78 731.38 function2
33.08 36.52 12.08 50000 241.60 241.60 function1
与
index % time self children called name
<spontaneous>
[1] 100.0 0.00 36.52 main [1]
24.44 12.06 49900/49900 function2 [2]
0.02 0.00 100/50000 function1 [3]
———————————————–
24.44 12.06 49900/49900 main [1]
[2] 99.9 24.44 12.06 49900 function2 [2]
12.06 0.00 49900/50000 function1 [3]
———————————————–
0.02 0.00 100/50000 main [1]
12.06 0.00 49900/50000 function2 [2]
[3] 33.1 12.08 0.00 50000 function1 [3]
———————————————–
不想再细说下去,自己琢磨去吧。
//test.c
#include <stdio.h>
int main(void)
{
printf(“Hello World!\n”);
return 0;
}
最常用的方法是使用 POD(Plain Old Documentations) 来进行多行注释。方法如下:
=pod
codes to comment
=cut
注意:=pod =cut只能在行首
按照传统,我们首先用Lua实现一个”Hello World”程序:
#
print(“Hello World”)
如果你使用的是独立的Lua解释器,则运行程序的方法很简单:你只需将你的程序文件名传给解释器(通常名为lua)。比如,如果你将上面这个程序写入到一个名为hello.lua的文本文件中,然后通过如下命令行启动它:
#
prompt> lua hello.lua
下面是一个稍微复杂一点的例子,下面这个程序定义了一个函数来计算阶乘。它让用户输入一个数字,然后打印出它的阶乘。
#
– defines a factorial function
#
function fact (n)
#
if n == 0 then
#
return 1
#
else
#
return n * fact(n-1)
#
end
#
end
#
print(“enter a number:”)
#
a = io.read(“*number”) — 读入一个数字
#
print(fact(a))
如果你将Lua嵌入到一个应用程序中运行,比如CGILua 或者 IUPLua,你需要读一下相关的手册(或请教一下能人)去了解如果运行你的程序。不过,Lua还是Lua,无论以哪种方法使用,我们在这里看到的大多数东西都还是有效的。我们推荐你使用独立的Lua解释器(一个名为lua的程序)来运行你的第一个练习程序。
1.1 程序块
Lua执行的每一段代码,比如一个文件甚至交互模式下的一行指令,都可以称为是一个“程序块”。简单来说,“程序块”就是一组语句序列。
语句的结尾加分号的写法是可选的。一般来说,我只是在把多个Lua语句写在同一行的时候,才用分号间隔,当然,这是一个习惯问题。换行符同样可以用来分隔语句。举例来说,下面这四种写法都是正确的,而且等效。
#
a = 1
#
b = a*2
#
a = 1;
#
b = a*2;
#
a = 1 ; b = a*2
#
a = 1 b = a*2 — 不推荐这种写法,不过确实可以这样写。
程序块可以简单到只有一条语句,像那个”Hello world”的例子,也可以是一组语句和函数的混合体,像前面的求阶乘的例子。你想让一个程序块有多大,它就可以有多大。因为Lua也被用作是一种“描述数据的语言”,所以,几兆字节尺寸的程序块并不鲜见。Lua解释器处理这些毫无问题。
除了将你的程序写进一个文件以外,你还可以使用Lua解释器提供的交互模式。如果你启动lua时不带任何参数,你就会看到这样的提示符:
#
Lua 5.0 Copyright (C) 1994-2003 Tecgraf, PUC-Rio
#
>
然后,你键入的任何指令(比如 print “Hello World”)会在你按下回车后被立即执行。如果想离开交互模式的解释器,只需要键入一个“文件结束符”(在Unix系统中是Ctrl- D,DOS/Windows中是Ctrl-z),或者调用OS库的退出函数(键入:os.exit() )
在交互模式下,Lua一般将每一行都看作是一个程序块。但是,如果它检测到这一行无法构成一个完整的程序块,它就会等待进一步的输入,直到其构成了完整的程序块。当Lua等待进一步的输入时,它会显示一个不同的提示符(一般是>>)。因此,你可以直接在交互模式下输入多行的定义式,就像那个求阶乘的factorial函数。当然,在一些情况下,将这些程序写入文件,再用Lua执行这个文件更方便一些。
你可以让通过 –l 参数让Lua解释器顺序地执行一组脚本程序。举例来说,如果你有一个文件a,里面只有一条语句:x=1,你还有一个文件b,里面也只有一条语句:print(x),则命令
#
promt> lua –la –lb
会依次运行a和b,并打印出“1”。( -l 参数实际上调用了 require 函数,这个函数会查找指定路径下的文件。所以,在前面那个例子中,如果你不写明a和b的路径,就无法正常运行。我们将在8.1节详细讨论require函数)
你可以使用 –i 参数告诉Lua解释器在执行完指定文件后,进入交互模式。比如:
#
prompt> lua -i -la -lb
将先执行a中的程序块,然后执行
Analytics Plugin created by Web Hosting