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: , ,

Linux启动项机制

December 10th, 2008

通常我们都会希望一些服务在系统启动的时候能够自动运行,比如网站的服务,SVN服务等等。在Linux下面和这个功能有关的文件在/etc/rc.d(或者/etc, 不同的系统不一样)下。在这个目录下我们应该可以看到rc.0, rc.1, rc.2, rc.3, rc.4, rc.5, and rc.6, 他们分别对应于不同的运行模式,其中0和6保留为停机和重启。其余的模式在不同的机器上的定义不一定相同,我们可以查看/etc/inittab来找到自己系统上的默认模式和对于其他模式的说明. 在SuSe Linux下该文件的内容为:

# The default runlevel is defined here
id:5:initdefault:

# First script to be executed, if not booting in emergency (-b) mode
si::bootwait:/etc/init.d/boot

# /etc/init.d/rc takes care of runlevel handling
#
# runlevel 0  is  System halt   (Do not use this for initdefault!)
# runlevel 1  is  Single user mode
# runlevel 2  is  Local multiuser without remote network (e.g. NFS)
# runlevel 3  is  Full multiuser with network
# runlevel 4  is  Not used
# runlevel 5  is  Full multiuser with network and xdm
# runlevel 6  is  System reboot (Do not use this for initdefault!)
#
l0:0:wait:/etc/init.d/rc 0
l1:1:wait:/etc/init.d/rc 1
l2:2:wait:/etc/init.d/rc 2
l3:3:wait:/etc/init.d/rc 3
#l4:4:wait:/etc/init.d/rc 4
l5:5:wait:/etc/init.d/rc 5
l6:6:wait:/etc/init.d/rc 6

…………

和其他大多数的Linux版本不同,SuSe没有提供一个rc.local的文件用来定制用户的启动程序,该脚本仅运行一次。在SuSe的论坛上我找到了两种方法可以替换rc.local.

首先要创建rc.local,然后向其中加入自己的运行脚本。可以通过yast2来将其添加到启动项,yast2是SuSe的一个基于GUI的启动控制程序。如果你在命令行下工作可以使用chkconfig命令: chokconfig -add [filename], 在我的SuSe上文件的名字不能是rc.local, 貌似中间的那个.不被接受,所以我改成了rclocal。

如果用命令行方式需要在rclocal的前面添加:

#!/bin/sh
### BEGIN INIT INFO
# Provides: rc.local
# Required-Start: $network $syslog
# Required-Stop: $network $syslog
# Default-Start: 3 5
# Default-Stop: 0 1 2 6
# Description: [your description]
### END INIT INFO

来配置该启动项的一些参数。这里的含义是rclocal会在3和5模式下被启动。

参考链接:

http://forums.opensuse.org/archives/sf-archives/archives-programming-scripting/317339-there-no-rc-local.html

http://www.linux.com/articles/114107

Author: gleery Categories: Linux Tags: , , ,