阅读《活法》

September 25th, 2009

知道《活法》这本书很久了,这是第二次读,而且大体上算是完整的翻阅了一遍。第一次去读这本书的时候, 我正迷茫于人生的真正意义到底是什么,原有的人生目的随着时间的推移已经无法再成为内心的支撑,于是我找到了这本书。对于人为什么而活着,稻和盛夫是这样回答的:

当有人问“人为什么来到这个世上”时,我毫不犹豫地、毫不夸耀地回答“是为了比出生时
有一点点的进步,或者说是为了带着更美一点、更崇高一点的灵魂死去。”

读到这句话时,有种顿悟的感觉,人生就是对灵魂的修炼,简单而又如此深刻,深刻到足以撑起人生的漫漫征途。

第二次读,一口气阅毕,亦觉得颇有感悟,截取一些片段于下:

我们内心有个吸引灾难的磁石。生病是因为有一颗吸引生病的羸弱的心

无论我们年纪多大,都希望自己是拥有梦想、前途一片光明的人。没有梦想的人就不可
能有创造性。无法获得成功,也不可能成长为有用的人。为什么呢?因为通过描绘梦想、锐意创新、
不断努力,人格才能够得到不断的磨炼。在这个意义上,我想强调一点——梦想和愿望就是人生的跳
板。

德高者以高位,给功多者以褒奖

释迦牟尼的寓言:

——深秋的一天,枯木瑟瑟中,有位路人急急忙忙地往家里赶。猛一看,脚下散落着很多白色的
东西。再仔细一看,原来是人的骨头。为什么在这里会有人骨呢?——令人毛骨悚然又不可思议,他
继续前行,一头正在咆哮的猛虎朝他迎面走来。
路人大吃一惊,原来是被这只猛虎吃掉的可怜的同路人的骨头啊!他一边想着一边慌忙转身,朝
来时的路飞快地逃跑。但是,似乎是迷路了,他竟然来到了悬崖峭壁前,悬崖下面是波涛汹涌的大海,
后面是老虎,进退两难之中,路人爬上了一棵长在悬崖峭壁边的松树上。但是,老虎也张开了可怕的
大爪开始往松树上爬。
现在真正完了,正在万念俱灰之际看见眼前的树枝上垂下一根藤条,路人顺着藤条哧溜了下去.但
是,藤条在中间断了,旅客被悬在空中,不得上下.
上面老虎舔着舌头,虎视眈眈.再向下看,波涛汹涌的大海上有赤、黑、青三匹龙严阵以待,要
把他吃掉。上面还传来吱吱的响声,抬眼一看,黑白两只老鼠在啃藤条的根部。
这样上去,藤条被老鼠用牙齿咬断,路人不得不朝张开血盆大口的龙落下去。在这八面围困之中,
他认为首先应该赶跑老鼠,试着摇了摇藤条。于是,有温热的东西掉在脸庞上,舔一舔,是甜甜的蜂
蜜。原来,藤条的根部有蜜蜂巢,每一次摇动都会有蜂蜜掉下来。
他开始喜欢上甘露一样的蜂蜜味道。于是,竟然忘记自己已置身穷途末路之中——尽管处于龙虎
争食的夹缝中、且唯一的救命藤条也正被老鼠啃食——他一次又一次地主动摇晃这根救命绳索,陶醉
于蜂蜜的甘甜中。

在这个故事里,老虎表示死亡或生病。松树表示世上的地位、财产、名誉,黑白老鼠表示白天和黑
夜亦即时间的推移。人不断受死亡的威胁和追逐,但仍然执着于生命。可是,生命只是像藤条一样飘摇
无常地不可靠。

Author: gleery Categories: 闲话生活 Tags: ,

vim 单实例脚本

May 25th, 2009

在Windows上用过EmEditor的人应该知道用EmEditor打开的所有文件都会以Tab的形式共享单一的GUI,这样做的好处是,不过因为写程序的时候打开了太多的文本而把任务栏挤得满满的。在Linux下使用gvim却没有这么方便,每次打开一个文件都会新建一个新的实例,是在是很不方便。

网上常见的解决方法是使用-remote-tab选项打开,不过用过vim的人应该都会感到gvim内置的tab显示实在是很不好用,倒是一个bufexplorer的脚本非常受欢迎,该脚本以文本方式提供了tab功能,用起来非常方便。这个脚本有若干个衍生版本,我使用的是minibufexpl.vim这个版本。现在我们希望双击一个文件后能够在bufexplorer中添加一个新的tab,简单的说就是使用drop命令打开一个新的文件。

查阅vim的api(h function-list)我找到了一个解决方法,  vim提供了远程执行命令的api:

remote_send({server}, {string} [, {idvar}])
发送 {string} 到 {server}。发送的字符串是输入键的序列。函数立
即返回。Vim 的服务器端不对键进行映射 |:map|。
如果给出 {idvar},将 {serverid} 保存在以它命令的变量里,此后的
remote_read() 需要使用此值。
另见 |clientserver| |RemoteReply|。
该函数在沙盘里不可用 |sandbox|。

{仅当编译时加入 |+clientserver| 特性才有效}

这样我可以在命令行下执行:

gvim –remote-send “:drop [filename]” –servername “GVIM”

即可在现有的gvim实例中打开新的文件。将这一功能封装一下就变成下面的脚本:

#!/bin/sh
FILE=$1
GVIM=/usr/bin/gvim

SERVER=”$(gvim –serverlist | head -n 1)”

if [ "$SERVER" != "" ]; then
$GVIM –remote-send “:drop $FILE<CR>” –servername $SERVER
$GVIM –remote-send “:call foreground()<CR>” –servername $SERVER

else
$GVIM -f $FILE
fi

exit 1

该脚本在存在gvim实例的时候远程打开文件,否则启动新的实例。接下来只需要修改/usr/share/applications/gvim.desktop文件,将其中的gvim命令改为使用上面的脚本来启动就好了。

Author: gleery Categories: Linux Tags: , , , ,

gleery os kernel

April 29th, 2009

关于gleery kernel 的介绍似乎早就应该开始了。 gleery是一个非常tiny的os kernel,其实就它目前的功能来说只是一个bootstrap plus版。虽然功能很简单,但是学到的东西还是非常多的,而且最困难的部分也已经被跨越了。

gleery os kernel主要是大四上完成的,实现一个自己的os kernel总是一件很让人感兴趣的事情。我首先从阅读《自己动手写操作系统》一书开始,作为内核领域内的新手,这样的一本入门级的指导书可以省去很多盲 目的尝试。操作系统内核的编写在一开始的时候其实是面向机器的编程,需要了解很多Intel处理器的相关知识和汇编指令的工作方式。我觉得这是最困难的部 分,一旦克服了这一关,后面的工作就是纯粹的软件设计和实现的工作了。在编写的过程中我参考了很多资料,包括minix源代码,linux早前版本的源代 码,以及Intel处理器的手册和一些其他资料。

我执意要在Windows上开发这个os,所以也遇到了很多障碍。之前就花了很多时间去弄清楚怎么将gcc编译的obj文件和nasmw编译的o文 件链接到一起,并且声称没有PE头或ELF头的二进制程序。这方面的资料很少,因为大多数人都是在linux上做开发。不过在windows上的开发也给 我带来很大的便利,比如我用source insight建立工程极大的方便了代码的编写和阅读。

下面介绍一下我在开发中使用的开发环境和工具:

source insight:编辑器,以及minix代码的阅读器,同时提供了一键编译和一键调试功能。

一键编译主要是设置source insight 调用make.exe实现了,主要的流程在makefile文件里面控制。

一键调试则是调用bochs的程序,设置启动参数实现的。

有了这两个功能,开发过程就变得非常舒适了,代码的修改和调试可以马上看到结果。在此之前我需要在命令行里面编译代码,然后手动运行bochs,如果需要频繁的改动然后查看结果,效率会非常低。

编译器: dev C++ 中自带的mingw, 以及nasmw。

自定义的工具:自己用C写了一些工具用来生成最后的软盘镜像。

这次决定发布的版本只是一个demo版,仅仅演示了时钟和键盘中断的效果,以及一个IDLE进程。以后会发布一个更加完善的版本。

你可以从http://code.google.com/p/gleery/上check out到源代码

Author: gleery Categories: 程序设计 Tags: , ,

正确使用JDBC数据库连接

April 29th, 2009

今天在写程序是时候遇到一个很诡异的内存问题,程序没有缓存任何东西,但是却使用了1G的内存。Java程序出现内存问题一样非常难以调试,由于是 程序自动回收,反而难以从程序本身入手。通常的原因是使用了对象却没有释放,也许我们认为应该释放了,但实际却没有被释放,或者在一些被封装的很深的地方 占用了大量的内存而没有被程序员所察觉。

Java里面有一些能够帮助找到内存泄漏的程序,其中Java Memory Profiler比较好用,免费的工具而且是图形化的界面。跑了一便程序后发现在jdbc哪里累计了很多的内存。回头来检查程序,发现唯一有可能的地方是 Connection,之前不是很确定应该每次使用时创建新的Connection还是是使用一个,Java的文档里面也并没有说使用 Connection应该注意什么。所以 便共享了一个Connection。改了程序后再跑,发现内存果然没有飞涨了。很明显Connection会使得数据库操作中的大量对象无法被释放,从而 导致内存泄漏,每次创建新的Connection,使用完后释放则没有问题。仔细想想Connection更多保存着和数据库操作相关的本地对象,对于数 据库来说维持一个Connection,在不做任何操作的情况下并不是太大的负担。

之后在网上找了一下,看到有一个人遇到和我类似的问题,页面在这里

把他的代码转过来

  1. Connection conn = null;
  2. ResultSet rs = null;
  3. PreparedStatement pss = null;
  4. try
  5. {
  6. conn = dataSource.getConnection(USERID,PASSWORD);
  7. pss = conn.prepareStatement(SELECT SAVESERIALZEDDATA
  8. FROM SESSION.PINGSESSION3DATA WHERE SESSIONKEY = ?);
  9. pss.setString(1,sessionKey);
  10. rs = pss.executeQuery();
  11. pss.close();
  12. conn.close();
  13. }
  14. catch (Throwable t)
  15. {
  16. // Insert Appropriate Error Handling Here
  17. }
  18. finally
  19. {
  20. // The finally clause is always executed - even in error
  21. // conditions PreparedStatements and Connections will always be closed
  22. try
  23. {
  24. if (pss != null)
  25. pss.close();
  26. }
  27. catch(Exception e) {}
  28. try
  29. {
  30. if (conn != null)
  31. conn.close();
  32. }
  33. catch (Exception e){}
  34. }
  35. }
Author: gleery Categories: 程序设计 Tags: , ,

OpenMP的初体验和问题的讨论

April 29th, 2009

今天小试了一下OpenMP,VS2005和08版都支持OpenMP。 在工程选项的语言栏启用OpenMP的支持,还要记得在文件里面添加, 如果忘记添加这个头文件,运行的时候会提示缺少vcompd.dll。
一个简单的使用OpenMP进行并行优化的程序如下:
#include <stdio.h>
#include <omp.h>

int main(int argc, char * argv[])
{
#pragma omp parallel for
for (int i = 0; i < 10; ++ i)
{
printf(”%d”, i);
}

getchar();
return 0;
}

第二个例子看起来是这样的:

#include <stdio.h>
#include <omp.h>
#include <ctime>

int main(int argc, char * argv[])
{
clock_t t1 = clock();
int sum = 0;
#pragma omp parallel for
for (int i = 0; i < 1000000; ++ i)
{
sum += sum;
}
printf(”\ntime:%d\n”, clock() - t1);

printf(”%d\n”, sum);

sum = 0;
for (int i = 0; i < 1000000; ++ i)
{
sum = (sum + i);
}

printf(”%d”, sum);
getchar();
return 0;

}

在跑这个程序的时候我发现启用了多线程for的程序所耗费的时间反而远远多于正常运行的时间。
注意到在循环中 sum是一个共享变量, 如果要在多线程中正确对其累加是要使用同步锁的。
实际运行会发现,累加的结果和实际的并不相符,也就是说OpenMP这里只是做了简单的分割。
而且由于伪共享的问题,会使得Cache失效,从而增加了运行时间。

正确的代码如下:

#include <stdio.h>
#include <omp.h>
#include <ctime>

int main(int argc, char * argv[])
{
clock_t t1 = clock();
int sum = 0;
#pragma omp parallel for reduction(+: sum)
for (int i = 0; i < 1000000; ++ i)
{
sum += sum;
}
printf(”\ntime:%d\n”, clock() - t1);

printf(”%d\n”, sum);

sum = 0;
for (int i = 0; i < 1000000; ++ i)
{
sum = (sum + i);
}

printf(”%d”, sum);
getchar();
return 0;
}

增加的reduction表示每个线程使用本地的sum进行操作,在并行代码块结束后进行reduction操作,reduction的语法是

reduction(operation:var)

这里我们使用+号作为operation, 即进行累加,这样修改过以后,程序达到了并行的效果,而且得到了正确的结果。

从这个问题我们可以看出并行程序设计和传统程序在思维上的不同,对于大多数习惯了串行程序的程序员来说,要写出正确的并行程序并不容易。

Author: gleery Categories: 程序设计 Tags:

开始打理博客

April 28th, 2009

一直懒得写新的东西,pongba在他的博客上推荐大家从现在开始写博客,虽然一直也有这样的想法,却从来没有付诸实践。要想像pongba那样每次都写出一片精彩的长篇更是目前看起来相当困难的一件事,毕竟自己的写作功底还不行哈。所以决定从贴上几篇以前散落在其他地方的文章开始,丰富自己博客的内容。最近打算写的是语言与内存管理,希望能够将各种语言及其内存管 理的策略做一个介绍,目前还在写作中,以后再慢慢贴出来。

另外决定给博客换个主题,新的主题貌似很流行呢,在wordpress的主题下载里排第二,的确是很好看,所以就不管是不是和别人的一样了,先拿来用着。

Author: gleery Categories: 闲话生活 Tags: ,

避免过早的优化

March 30th, 2009

We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. (Knuth, Donald. Structured Programming with go to Statements, ACM Journal Computing Surveys, Vol 6, No. 4, Dec. 1974. p.268.)

避免过早的优化是编程中的一个观点,但是本文却是关于做事的。对程序员来说追求细节上的性能优化往往是得不偿失的,一些代码即使性能差一些也不会对整体的性能产生影响,真正重要的是系统中调用最频繁的热点部分才值得优化。这个观点也适用于做事。

我们总会希望事情变得越来越简单,简单到一个命令就可以自动化一件工作。但是这个自动化是需要成本的,在简化一件事情之前我们首先要明确这件事情是否值得简化。如果同样的问题反复的出现,在你的工作中持续的带来不爽的感觉,那么这时花一些时间去解决这个问题就是必要的。但是如果问题只是偶尔的出现,那么短暂的不方便即使忍耐一下也没什么。

这个感悟是在配置gvim的时候想到的,一开始我花了很多时间去安装各种各样的插件,学习了他们的用法,解决一些问题。不过我甚至都还没有大量使用vim的经验,所以那些插件是否真的对我的工作都有帮助。用掉的时间是否都物有所值还是未知数。就像firefox的插件一样,一开始处于好奇,尝试了很多插件,最后使用的只是其中的一小部分。

这个道理可以扩展到很多地方。比如项目的管理,那些方面是需要迅速解决的,那些是可以忍耐的。追求简单的生活但又不过分,不让这种追求成为一种不划算的负担,才是明智的做法。

微软Live图片搜索的新功能

December 18th, 2008

虽然不怎么用微软的Live Search,不过在试用了图片搜索的新功能后,还是不得不认可微软在图片检索方面的确走在了Google前面。

新功能允许用户在搜索结果中选定一副图片,然后搜索与其相关联的图片。之所以觉得这个功能好在于,大多数时候文字无法区分出图片的所有特征,所以搜索结果肯定不会完全匹配用户的意图,但是用户当然知道自己想要什么样的图片,只不过这个想法只存于用户的脑海中,这样就造成了用户和搜索引擎的沟通的障碍。而一旦搜索引擎具备了找出相似图片的能力就可以很好的解决这一问题。用户可以很快定位到自己想要的图片,然后获取大量的与此类似的结果。

Live 的搜索结果

Live 的搜索结果

我选择了右下角的Ipod作为我想要找的图片:

相关图片的结果

相关图片的结果

搜索的结果基本让人满意。不过显然改功能需要实时的对图片进行大量的运算,所以用户等待的时间会比较长。联想到微软亚洲研究院在SIGGRAPH上发Paper的能力,微软在图像处理上的技术的确不容小视。

下面是google的对比结果:

Google的对比结果

Google的对比结果

值得注意的是,Google的算法中显然将比较热门的ipod touch排在了前面。

Author: gleery Categories: IT时事 Tags: ,

OpenCalais——语义网的应用实例

December 18th, 2008

也许很多人对什么是语义网的技术还不是很了解。不过也许你可以从OpenCalais的应用中找到一些线索。

OpenCalais能够分析网页中的文本,并对其进行语义标注。语义标注的过程将利用RDF描述的数据,去识别文本中的一些词汇。下图是我选取的一段文本被标注以后的结果:

Calais

Calais

标注之后的结果是文本中的人名、地名、组织和一些专有名词都被识别并打上了不同的标签。要做到这一些需要比较全的数据文件,加上NLP的技术来进行一定的模糊匹配。我的感觉是做得相当的不错。

改功能支持Web Service,可以广泛的被其他网站使用。不过目前的版本并不支持中文。

Author: gleery Categories: 研究学习 Tags: , ,

关于语言机制的思考

December 12th, 2008

我们可以教会大猩猩手语吗?这听起来是一个不错的注意,也许我们像教一个先天聋哑的人类小孩一样去教一个大猩猩手语,我们会发现原来大猩猩也是能够使用语言的吗?

wiki上的Great ape language词条页面内我找到了这样的描述:

It is now generally accepted that Apes can learn to sign and are able to communicate with humans. However, they are not able to form syntax to manipulate such signs, a trait which appears to be limited to human language use.

从这里我们可以看出对于类人猿而言即使在人类的训练环境下也只能掌握有限的语言能力。

科学家的研究发现人类的语言能力很大程度上已经成为了一种本能。人在婴儿时期有着更强的语言学习能力,在这一阶段大脑的突触和神经元数量都是人的一生中的最高水平,即使婴儿由于一些原因使得大脑受损,其修复能力也远远强于成人。一种解释说如果婴儿能够在较短的时间内掌握语言,那么他们将能够更多的得到来至成人的指导,从而获得更大的成活率。

对于一直被认为和人类的出于进化史上最近的亲戚的猿类们显然缺乏我们在进化过程中形成的这种语言处理能力。

相比于教大猩猩学习手语,我对人类的语言本能的内在机制更感兴趣。语言学家也做过很多的实验来试图发现人脑在理解语言时的蛛丝马迹。其中一个有意思的结论是人类在理解句子的含义的时候实际上是遵循深度优先的策略,直接选取概率最大的路径进行解释,如果最后发现无法正确的理解才会回过头来从新扫描。在wiki上的David Swinney词条上我们还可以找到很多有意思的实验及其结论。

如果我们能够正确理解大脑的语言功能,我们能够用计算机来进行模拟这一机制呢?目前NLP的研究中大量使用了概率的手段,但是现有的手段仅仅只是停留在Shallow的层次上,仅仅只是在试图获取语言某一方面的局部信息,离语言的理解差得很远。

Author: gleery Categories: 研究学习 Tags: , ,