The original P2PSim ver 0.3 can not be compiled successfully with g++ 4.3. I have fixed the problem and provided the download of my revision on http://www.fosfer.info. The download link can be found within the “Open download” category. Only the compiling bug is fixed in this revision, while no any other code is touched. So it’s expected to work as same as the original version. If this download violates any copy right, please let me know.
2009年12月28日星期一
P2PSim-0.3修正版提供下载
我在http://www.fosfer.info上提供了修正后P2PSim-0.3版本的下载。我只是修正了P2PSim 0.3的版本无法在新的G++ 4.3上无法编译通过的问题。该版本的功能实现上未作任何修改,保持了和原版本的一致。下载在该站的Open download下。http://www.fosfer.info目前还在建站中,今后的发展目标是成为我和朋友们的工作室的主页,能提供各位有用的文档、资料以及代码。
2009年12月27日星期日
P2Psim分析笔记(7)-RPC机制
RPC(Remote Procedure call)的本意是,一台电脑通过网络来来执行另外一台电脑上的函数,函数执行的结果再送回本机。这个机制有很多实现和变形,比如xmlrpc, Soap, 我在这里不扯开了,大家google一下就知道了。因此按照RPC的概念,P2P中peer之间的相互访问都可以看作是RPC操作。因此在P2P的仿真中,仿真软件都不约而同实现一套简化了的rpc接口,这样在应用层的p2p协议只要用这套接口就可以不必理会底层网络通信的细节了。这篇中我给出了RPC实现的说明图。
图中,不同p2p协议通过调用Node中的doRPC()和asyncRPC()来发送数据给远程的peer。前者是同步的,也就是说,在没收到对方peer的回复或者超时前,本peer就一直死等。后者是非同步的rpc调用。在非同步的方式下,peer调用asyncRPC()函数会立刻得到返回,然后协议得到一个该次请求的句柄,可以理解成取货凭证。然后peer隔一段时间在通过rcvRPC()函数,用这个句柄来查询一下,这个远程调用是不是返回结果了,或者失败了(比如网络丢包)。这好比拿着取货凭证去取货一样。同样如果这个peer收到别人发送来的rpc请求,他也要提供处理相应请求的处理函数。当收到这个请求的时候,相应处理函数被调用。关于请求,我们迟点再分析。我们先逐个分析doRPC()和asyncRPC()的实现。
当Protocol类的对象调用了Node类中的doRPC()时,Node类首先通过_maktrunk函数把这个请求打包(为了更像一个网络报文?不知道),然后依次调用_doRPC_send()函数在这个报文上面加一个channel(libtask里面的多任务间的数据通信机制)把这个请求的trunk发给Network类的send()接口。Network根据拓扑算出这个报文到达对方peer的延迟,然后生成一个NetEvent事件放入事件队列里。当doRPC()发送了这个数据包后,立刻调用_doRPC_receve()来在这个报文的等待这个数据包上的channel上是否有数据过来,如果有,则从channel中取出这个rpc是否成功的信息再依次返回给doRPC()函数和上层的调用代码。如果成功,这个rpc请求中的返回值指针指向的数据结构已经被对方peer给改写了。以这种方式模拟rpc结果数据的返回。
当Protocol类的对象调用了Node类中的asyncRPC()接口的时候,机制稍微不同一点。asyncRPC同样调用_maktrunk()封装出一个trunk包,然后让_doRPC_send()函数发送出这个包,但是返回的rpc句柄(取货凭证)被存放到_rpcmap结构中暂时保存起来。然后asnycRPC()函数就立刻返回这个句柄给上层protocol的调用代码了。然后呢,上层代码在之后的事件里面可以时不时通过rcvRPC()接口来查询一下_rpcmap结构里面这个凭条对应的请求有没有得到响应或者是否出错了。
以上讲完了rpc请求发送的基本逻辑流程,接下来说一下rpc请求被接收的流程。上篇我说了,当EventQueue处理NetEvent事件的时候调用其execute()会导致Node中的Packet_handler()接口被调用。这个接口函数会区分,该消息对应的是rpc请求还是rpc应答。如果是应答的话,他就这个报文通过其channel(记得在_doRPC_send()中建立的channel么?)发送过去。 如果_doRPC_receive()正在等待channel上的数据,这个数据就会让_doRPC_receive()返回,完成同步RPC。如果这是一个异步的rpc,无所谓,这个数据就存在channel里面了,等peer调用rcvRPC()去查询和收取。
如果这是一个请求事件,那Packet_handler()就建立一个新task来运行receive()函数。这个函数中,这个事件中rpc的请求类型会被拿出来分析,对应不同的事件类型,protocol里面的不同事件处理函数会被调用。也就是说Protocol对象实例中的相应RPC处理函数“被”执行了。根据执行结果,receive()函数构造出RPC响应数据包,然后再通过Network类的send()结构最终又变成NetEvent事件插入到事件队列EventQueue里面去了。至于RPC的响应如何处理,上一段已经说过了。
P2Psim分析笔记(6)- 仿真中的事件机制
这几天由于P2Psim的分析进度不是很快,所以一直也就没有更新分析笔记,希望大家见谅。在前几篇中,我已经大体介绍了P2Psim的初始化过程。对初始化的分析,到上篇就告一段落。由于我是一边分析一边写笔记,所以有些细节方面可能存在遗漏和错误。如果各位在自己的分析中发现,不妨联系我。在每篇笔记的图片中,有我的邮件地址的水印。
接着之前的分析,本篇主要介绍了P2Psim的运行机制。这部分的理解,是以后用P2Psim来添加自己的p2p协议的基础。这篇的介绍不涉及太多细节,因为在我的分析中,发现Node类的实现中有太多的细节需要说。所以在这里我只是给大家一个总体的介绍。如果大家去做代码分析,我建议大家分析sillyprotocol,而不要一上手就去看Chord协议。我个人的感觉是,Chord协议涉及太多协议本身的机制,它的机制本身的复杂性,很大程度上会干扰大家对仿真中的消息机制的分析。而sillyprotocol几乎没有什么代码和任何协议机制。因此是一个很好的切入点。
按照惯例,我给出了分析的简单图例。由于这图是用office的onenote画的,虽然画起来很方便,但是onenote的画图功能实在太弱了,所以不同意义的先只能用颜色区别,而无法用线形来区别,大家只能凑合着看了。
图中左上角的EventQueue是我介绍的切入点。在之前,我介绍过,他的运行机制就是在不停的调用他的advance()函数从消息队列里面取出事件,然后每次取出消息就去kick一下消息发生器类EventGenerator,然后再对取出的每个event对象,调用其execute()函数来完成相应的操作。那么EventQueue中消息的来源主要是两个: EventGenerator类或其子类;和Node类。
先看EventGenerator类。这个类在把自己注册到EventQueue实例里面的时候就把仿真结束消息(exit)和各个peer加入仿真的消息(join)加入了队列。前者是SimEvent类型的消息,后者是P2PEvent消息。SimEvent类型的消息只有一个用途,就是结束仿真。P2PEvent事件的用途就是通知各个peer在不同的时候做不同的事情,比如join,crash和lookup这些。不同于其他的仿真软件,如OverSim,P2Psim中P2PEvent事件是由EventGenerator做中心控制的,而不是由各个peer自己控制的。换而言之,EventGenrator控制了全体peer的行为模式。这点简化对于homegeneous的仿真而言是好的,写代码就容易多了。如果要做geterougenous的仿真就困难一点了,不过也不是大问题。
第二个事件的发生源是Node类。Node类封装peer作为网络结点的角色。对上层p2p协议,Node提供了RPC调用接口。然后把对应的RPC请求和应答转换成网络报文的传输。在仿真中,报文的发送和接受都被转换成NetEvent网络事件。当Node要发网络数据包的时候,他就从Topology对象提供的接口计算出报文到达的延时,然后生成一个报文到达的NetSim事件,放到EventQueue里面,等待EventQueue到时候进行处理。
介绍完事件的发生源,再说说事件的处理。之前说过,EventQueue在取出Event时候,会调用其execut函数来处理事件。对于不同类型的事件,其execute机制不同。 最简单的是SimEvent的,立刻就通知系统结束仿真了,具体代码各位自己去看。其次是P2PEvent。如果消息对于的操作是EventGenerator让peer join或者crash,他只是把protocol中对应的_alive进行置位和清位。如果是其他操作,如chord中的lookup,这类。他会对应找到protocol对象中的函数调用来完成处理。比如lookup事件, P2PEvent 就把Event中对应的node对象找出来,调用他的lookup()函数.
如果处理的是NetEvent事件,它的execute会根据事件的类型进行区别对待。之前我提到,Node会把RPC操作转变为网络报文传输,因此NetEvent对应不同网络报文也分两类:请求和应答。如果这个事件对应的是请求,它就让系统为对应的接收结点生成一个新task来跑Node::receive()函数,让node来接收这个“网络数据包”。否则,他就把这个数据包发送到对应的channel去,让等待接收RPC回应的node的()来接收这个回应。
2009年12月23日星期三
P2Psim分析笔记(5)-EventGenerator and Observer
本篇笔记,主要是跟踪taskmain()函数中EventGenerateor::parse(event_file)。本篇主要涉及EventGenerator的构造流程,其中对churnEventGenerator类和ChornObserver类进行分析。下面的图示给出了EventGenerateor::parse()函数的调用流程。
图中EventGenerateor::parse()的调用很简单,首先读取eventfile 里面关于eventgenerator和observer的名字。生成了一个generator实例,然后通过thread()把对应的eventgenerator的任务个激活。最后再生成observer实例。这里我分析了ChurnEventGenerator 和ChurnObserver两个类。按照我的理解Generator主要用于生成对应protocol的node的初始化事件,比如node什么时候开始活过来,以及对eventqueue类实例化和进行激活等操作。observer 的设计本意是用来统计和记录仿真中的各个事件。在P2Psim的设计中,observer的实例化中,observer把自己注册到各个node对象中,这样每次node发消息的时候,在消息队列处理消息的时候,都会把这个消息上的observer拿出来,调用一下他们的kick()来修改observer中的统计信息。
图中,首先EventGenerator::parse()调用工厂模式生成了eventgenerator实例。我们以churnEventGenerator为例。churnEventGenerator在构造对象的时候,首先读取了所需的参数。图中列出了所有参数,这些参数的具体用途以后再分析(目前我也不清楚,呵呵)。然后实例化了消息队列,并把自己注册为消息队列的observer,这是一个特殊的observer(具体的用途目前也不清楚,估计是每次消息队列处理消息的时候,都能被调用一次)。
在消息队列的实例化中,消息队列eventqueue,建立了一个特别的channel,然后就调用自己的thread()触发了run()函数变成一个并发任务。run函数首先会在这个channel上等待一个go消息(这个消息会由eventGenerator的实例触发,见图中黄绿色箭头),当收到这个go消息,run()就循环调用advance()函数来处理消息队列里面的每个消息。在处理每个消息的时候,每个消息上的observer会被kick()一下,然后消息队列会执行event上的execute()函数来处理这个消息对应的事务。
在EventGenerator::parse()生成eventgenerator后,第二件事情是调用了这个实例(churnEventGenerator为例)的thread函数,然后这个消息发生器对象就开始作为一个并发任务开始运行其run()函数了。在其run()函数中,我们可以看到generator的主要工作了:首先生成了一个仿真结束消息,然后从network实例中要来了所有的node信息,把他们都维护在本地的数据结构里面,并把wellknown结点告诉他们,这样他们一开始就能知道他们到那里去找access point。然后设置每个node加入p2p网络的事件。当然,wellknown结点是最早加入的(不然别人找不到他了)。最后给eventqueue发一个go消息,eventqueue就开始处理消息了,整个仿真就开始了(但是由于没有调用yield(),当前任务还没进行切换,所以在物理上那些任务一个都跑不起来)。
再回到EventGenerator::parse(event_file)函数,最后一步是通过工厂模式建立了observer对象实例。以churnObserver为例,他的工作也很简单,从Network对象实例里面得到所有的node信息,把自己的指针加入他们,这样他们发送消息在消息队列处理时observer就会被触发了。
总结: eventGenerator 是注册在eventQueue上的observer,而普通observer是注册在node上的。
2009年12月22日星期二
P2Psim分析笔记(4)-Topology 和Network
这部分的调用是taskmain函数中的Topology::parse(topology_file)引起的。在pase函数中,首先从topology_file里面读出了topology的名字,例如Euclidian拓扑, 以及对应的failure模型。至于failure模型,好像是用来制定数据传输中的丢包策略的。这个目前不是我的兴趣所在,所以我也懒得去仔细分析了。如果在topology_file里面不指定的话,在这里会默认提供一个无丢包的nullfailure模型。
在生成topology和failure模型中,他们的构造函数都不会做什么特别的工作。然后这两个对象top和fm被作为参数来构造Network的对象实例。在Network对象的构造中,topology和failure模型会被保存到Network对象里面。以后只能有Network的实例来访问了。最后Network对象构造中会调用thread来让run函数作为一个task来跑。这个函数中,Network实例开了一个channel(libtask中task进行通信的机制),然后就不断从这个channel读取来自topology对象的Node(也就是peer)信息。然后存到自己的_nodes成员中,这个成员是IPaddress 和Node指针的一个map。
最后,Topology::parse()调用了topology对象的parse完成了topology_file的剩余部分的解析。这里要注意toplogy对象(top指针 )是指向Topology类的一个子类的对象,比如Euclidian类的对象。 接下来,我们拿Euclidian拓扑来举例,这个对象按照
IPaddress x,y
的格式来解析peer在空间中的位置,以及用ipaddress来标识peer。解析出每条记录,都通过工厂模式,构造出一个Node类的子类的对象,除了保存在自己的_nodes成员中(也是一个IPaddress 到node的map),通过channel发送给Network对象的run函数。图中的黄绿色箭头表示出这个联系。
2009年12月20日星期日
P2Psim分析笔记(3)-taskmain函数流程
然后,taskmain让EventGenerator类根据event_file生成了对应的事件发生器(EventGenerator)的对象,这里采用了工厂模式,根据配置文件生成对应的事件发生器。同时还生成对应的观察者对象。 生成的发生器对象也是一个从Threaded派生的家伙,因此此刻第三个并发任务也开始运行了。
最后,taskmain遍历了所有的node对象,让他们完成初始化。随后完成所有工作退出。
2009年12月19日星期六
P2Psim分析笔记(2)-程序架构简述
这是我整理P2PSim这个仿真软件包的第二篇笔记。第一篇是《P2PSim在g++ 4.3下的编译》,在第一篇里面介绍了P2PSim 0.3在编译和按照中的碰到的问题以及解决方式。本篇主要给出P2PSim的实现架构,帮助需要进行代码分析的朋友对P2PSim能有个大体的构架了解。在些这篇时候,作者也还未完成对整体代码的通读,所以对全局的掌握还不充分,如有错误,请各位指出和包涵。
首先是P2Psim的实现基础。这个软件包的实现是基于单进程多任务方式工作的。他本质上是基于一个叫LibTask的C语言软件包来实现在单个进程内进行多个任务的调度和切换。这个包在他的源代码的/libtask目录下。 这个包是MIT开发的,目前在google code的网站上有登记,地址是http://code.google.com/p/libtask/,可以在这个网站上查到这个库的基本api的说明。可以直接看这个说明来理解这个库的实用,而不需要去看/libtask目录下的代码来分析到底这个库在做什么。此外,在P2PSim里面,作者把这个库封装到了Threadmanager和Thread两个类。前者Threadmanager用来封装全局的task的pool的,而后者封装了各个task的api。这样P2PSim就实现了C++这级的多任务调度。
其次,我把kikikind老兄的类继承图重新贴一遍,来帮助大家理解程序架构。在这个图里面,我们看到从threaded类一共派生出EventQueue, Network,和EventGenerator三个类,这三个类就是程序在运行时候的3个主要并发任务。
至于图中的其他部分,等以后的具体分析的时候再慢慢说明。
因此,综上所述,P2Psim是一个根据libtask所提出的架构所写的一个程序,因此在/p2psim目录下,main.c程序里面没有main函数,而是taskmain函数,这个函数会被libtask作为第一个task而调用启动,功能类似main函数,连调用参数都差不多。然后在这个taskmain中,间接建立了上述其他几个并发任务。
到这里,读者应该对p2psim的大体构架有个简单认识了。 下次我打算把taskmain函数里面的初始化顺序介绍一下。
2009年12月18日星期五
2009年12月17日星期四
一位亿万富翁的素食原则(zt)
旺度居士
全球500强之一的AT&T公司亚太地区前总裁温先生今天视察了我们公司。他现在是一个拥有数亿资产的香港出版公司董事长,一位慈眉善目的中年人。
中午由我做东,请他吃饭。亿万富翁要吃什麽呢?我有些茫然。珠海虽然颇多山珍海味,但要让温董吃得满意,究竟需要怎样的排场?
谁料温董轻言轻语∶“方便的话,我就吃素!”於是,我们顺便进了怡景湾大酒店旁的西餐厅。
温董、刘先生、我及LD一行四人,点了四份商务套餐。我们的三份,有荤有素;温董的那份,还真是全素。
席间,我向温董请教吃素的益处。温董的一番素食理论,听得我心服口服┅┅
(温董的话)
简单原则
一谈到吃素,就会被许多人问及“修行”的事,总是被弄得很茫然,不知道应该回答什麽,每每想起前一段时间的一次对话,只涉及到一些简单原则,比谈“修行”容易多了。起因是去日本交流,这天中午他们知道我是素食者。
“你什麽都不吃吗?”(每个人都忙著劝别人吃,有人客气的问。)
“我刚才吃了一个苹果。”(我礼貌的回答。)
“他是一位素食者。”我的同事放了个炸弹。客气的寒暄显然不如这个话题有趣,大家如同看斑马一样一起盯著我。
“你信仰什麽宗教吗?”(为什麽每次都要问同样的问题。)
“没那麽复杂,只是生活方式略有不同。我的原则很简单,尽量不伤害别人。”
“可动物不是人!”
“我们喝著牛奶长大,它辛苦种地让我们吃,当它哭著求你不要杀它和它的小孩,你是否下得了手?你是否忍心?小时候大家都玩过老鹰捉小鸡的游戏,那表示它们的母亲不希望它的小孩受到伤害。它们打不过你。但你不会利用你的强大去欺负别人吧,”
“那你肯定反对我们吃肉。”
“我不会把刀架在你脖子上的,这也是一个简单的原则,如果你喜欢吃苹果我逼著你吃梨,那也是暴力。你快乐著你的快乐,我幸福著我的幸福,於是天下太平。只是你要了解自己在做什麽,结果是什麽,并且肯承担,那你有权选择你想要的生活,不一定要和我一样嘛。”
“可是你不伤害别人,别人也会伤害你。”
“你总不能因为别人偷了你的自行车你就去偷别人的自行车吧。”
“养那麽多鸡不就是给人吃的麽。”
“好像在南北战争时期就有人说∶黑人天生就是奴隶,他们的儿子、儿子的儿子天生就是奴隶。”
“我很佩服你,面对这麽多美食能忍得住。”
“我不会虐待自己的。他们对我没有吸引力,我不需要忍的啦。我刚才已经吃了一个苹果,香甜而且多汁,(席间已经有人为我点了一盒牛奶),瞧,我还有牛奶,并且每个人都很关心我是否够吃,够营养,小小的善意就得到了很多回报,这世界真的很公平的。”
“你真的适合信一个什麽教。”
“这跟宗教没有关系,只是一些简单的原则,我不会啃著鸡腿给我的儿子讲动物是我们的朋友,这样做的结果是他不仅没有学会仁慈反而学会撒谎,因为你心口不一。有很多事情是我们在幼儿园里就学过的,比如说∶大家都是好朋友、撒谎不是好孩子、自己的事情自己做、有礼貌、帮助别人、好好学习、天天努力向上、讲卫生、爱劳┅┅,这些都是极其简单的原则,就是要认真地去做。总不能长大了还不如一个小孩。”┅┅┅┅
时间久了,很多对话记不住了,不外乎把这些简单原则应用到生活和工作上,但是这些被重新提及的简单原则已经跨越午餐成为延续到下午的话题,也许还会延续到他们的生活中。许多人连小孩会的事都不会做,小孩懂的事都不懂,却谈论著这个经典那个法门,不知道爱的人满嘴都是感动,自私的人却在谈著奉献。我真的不知道什麽是“修行”,那麽复杂的事还是交给那些“大修行的人”吧,让我简单的活著,多做事少说话,这也是一个简单的原则。
我为什麽成了素食者
当您真正了解肉类是污秽不洁的,又具传染病的尸首时,您能再面无惧色的狼吞虎咽吗?
在我逐渐弃肉而吃素的过程中,我没作过任何所谓的"牺牲",所有食物没勉强放弃过一样。我虽相信,人在生活中善自保重身体,是信仰的一部份,但我个人在弃绝肉食中,与信仰毫无关联。
我不吃任何肉食和任何维他命丸,也健康的活了半辈子。我在美国旅行多次,常在饭馆和别人家中吃饭,桌上虽也有肉类,但丝毫不曾影响我的饮食与情绪。弃肉吃素的经过,未曾使我作难,也没有勉强的感觉。让我慢慢道来吧猪肝的脓包里竟有一窝煮熟的小虫,牛的一整叶肺给结核菌蚀烂了;动物的病菌会寄生在人体上。
....在旅行时,有一天吃肝咬了两三口,觉得味道不对劲,再用刀子一切,真把我吓了一跳,脓包里竟有一窝小虫,早己煮熟了。从那天起,每逢看见肝我就反胃。
....我本来最爱吃碎牛排,就是用绞肉机绞碎的。听别人说,商人常搀杂各种劣等的零碎物,所以每次我都亲自挑选一块漂亮的牛肉,叫他当面绞碎。我觉得这样作很精明。
....有一天,我发现自己并不精明。因为排在前面的一位老兄,等著绞他的猪肉。同一个绞肉机,既不消毒,也不洗,它内部的构造我更清楚。这时我才领悟到前面的人留下半磅猪肉给我,而我的半磅混合肉要留给后面的那位顾客。从此,碎牛排再也不能逗引我的胃口了。
....我虽不再吃碎牛排,但是牛肉仍是我所喜爱的,直到一件事震撼了我,我才全然断绝牛肉!!
....事情是这样的,我的邻居从牛群中挑了一只最棒的母牛,供应他自己的牛奶。某天,卫生员来检验,说只牛有结核病,应予销毁。邻居说他不相信,置之不理,后来,另外的检验员又来检查,报告的情况相同。
....我的邻居仍不肯相信,他勉强的把牛送往一个较大的屠场,获得许可,观看切割。出现在他眼前的,是一整叶被结核菌蚀烂了的肺!
....回到家里,他极为烦恼。他得的那笔代价还不错,比同量的肥料价钱贵多了。但是,他一直在想,那只牛身上的其他部分,是不是健康无病菌呢?是不是可以食用?
此事过后不久,我领著班上的学生去远足,路过该屠房,大家看著各种动物的尸体,在吊车和输送带上运送著。我就问那位作向导的政府验肉员∶『请问老兄,如果一头牛害结核病,一叶肺烂坏了,您们怎样处理呢?』
....『我也请问你,你的苹果上有个烂斑,你怎麽办?你还不是把它削掉,然后吃下去吗?我们也是一样作。』....我注意到学生们脸上吃惊的表情。上次我曾向他们讲过那只病牛的故事。等出了屠场,我问他们削苹果和割牛肉是否相同。
....『不同,开玩笑!』异口同声的否定著。他们说∶『病肺的血液会周流全身。』於是我又向他们指出另外的不同点∶动物的病菌会寄生在我们的人身上,而苹果的酶菌只会活在果菜上面,再者,它也不会周流回圈。就算把苹果的烂疤吃下去,也不致于害病。
....这样一来,过去使我讨厌的某些肉食,越发使我讨厌了。
鸡场里,那些垂头丧气、屁股潮湿的劣等鸡都进了市场,加★工场。
....过去我爱吃鸡。但参观附近的一个养鸡场之后,这方面的食欲也没有了。我看到,养鸡人天天巡视鸡房,把病鸡和少下蛋的鸡挑出来,送去市场。那些垂头丧气、屁股潮湿的家夥,都进了加工厂。使我吃惊的是,至少在那时候,根本就没有任何检验工作。胃好像告诉我,别再把死鸡送进我的皮袋里去了!
★某些山涧里,有百分之九十的鱼的染患癌症。
┅┅鱼,我还是吃,有时还开玩笑的说∶「鱼一定是乾净的,它们起码每天洗一次澡呢!」....某次,同朋友去亚利桑那州某山涧钓鱼,我搞不清到底是甚麽毛病,但我知道所钓到的鱼中,将近二分之一是有肿瘤的,或在内部,或在外部,看了令人倒胃口。查阅有关资料,我才从政府报告得知,有些山涧里,鱼癌流行,尤其是鳟鱼。其染病率有的高达十分之九。
★那些小鱼
┅┅还有,一些装罐的小鱼,如沙丁鱼等,根本就没有清洗过,连五脏,带粪便,一股脑儿的装进铁盒里去.................
请珍爱生命
看见报上的一幅图画,一口烧热的油锅中弓身著一条鳝鱼。图画的插图大意是说,下油锅的鳝鱼极力弓起身体,厨师不解,拿出鳝鱼用刀剖之,才知其腹内怀有一条小鳝鱼,它是为了保护腹中的小生命,努力的弓起了腹部。
听友人讲起一件他目睹的很悲惨的事。一条有黑缎般光亮皮毛的雄性狗,离开刚下狗娃的花狗准备到街对面不远处的一家肉食小店去拾一些骨头。大约是被爱情及爱情的结晶冲昏了头脑,它从北向南穿过十字路口时,没注意到一辆微型客车正从东风驰电掣般开来,“21712;”的一声,被车撞了个正著。车子几乎连速度都未减一下,就开跑了。车子刚刚离开,狗就在车子喷出的废烟中,一个鹞子翻身站起来,撒腿往肉食店跑去。在它被撞倒的路中间,有滩红色的血慢慢向四周流动和凝固,象一个心的形状。血中间漂浮著几根黑亮的毛。
黑狗迅速地跑到小铺子,用嘴拾起一根粗大的带肉的骨头,转身又飞一样奔回它的花狗和小狗娃的身旁,并将拾来的食物喂给了它们。这一系列行为在不过10分钟内全部完成,而且,当它把捡到的骨头转给花狗时它就无力的垂死般地倒在了花狗的身旁。谁也不会想到,从路上站起来跑掉时,“身手敏捷”的黑狗怎麽会在一瞬间死去。
友人说,黑狗将骨头转给花狗时,它听清了它们相互间那种类似安慰的,狺狺的低语。与它们的声音不同,它们的眼睛都充满了那麽深深的哀痛,悲伤。尤其是黑狗的眼睛,似乎是含著泪光,充满对生命的留恋,它那麽固执地看著自己的爱侣,看著自己的孩子,连眼睛都不转一下。那种目光,即使铁石心肠的人看了都会心颤。
我还知道,几年前冰岛政府否决了原本拟定的再次允许捕鲸的计划,原因是“找不到能使鲸迅速了结痛苦的捕鲸枪”。
在引起我们兴趣的事件日益增多的日益刺激的今天,珍爱生命这件事显得书生意气。然而,假如阅读黑狗含泪的眼睛,鳝鱼竭力弓起的身体,以及听到冰岛政府人道的尊重生命的决定,心不猛烈的跳动,并向生命致以你最诚恳的敬礼,那麽,活著就失去了它最本质的快乐。不是吗?
我在这样一个阴郁的漫长午后,开著起亚嘉华行驶在珠海的情侣路上,一遍一遍的回想温董的话和这三个与生命相关的片断,它们就象挂在屋檐下风乾的萝卜条,让你记忆生命曾经是那麽饱满,丰润和微光闪烁。而珍爱生命,就象用泉水去浸泡萝卜干,无论是哪一种形式的浸泡,都会让人看见生命恢复原状的过程,一种世间最耐人寻味的过程,一粒种子到开放花朵的过程。
听了温董的一席话,我暗下决心,一定要成为一个素食者。
P2PSim在g++ 4.3下的编译
在安装中,我用的是Debian 5.03 lenny平台。g++是4.3版本。下载到的p2psim 0.3版本无法在g++4的版本上进行编译通过。网上最简单的做法是用老版本的linux。这是我不屑做的事情。经过一个下午的折腾,终于把所有编译问题都解决了,在这里做一个问题解决的总结。以便后来人。
我碰到的问题一共有6类。按照出现和解决的次序分别为:
1:hash_map STL错误, C++库更新造成的问题
2: strcmp未申明, g++对缺省include变严格了
3:类函数 Node:xxxx: C++语法版本
4:代码错误 vividi: 作者的低级错误
6:bighashmap.cc include问题: 还是觉得是C++语言机制问题
5:STL里的assert错误: 不清楚原因
1. hash_map STL错误
这个问题g++会提示用到了ext/hashmap这个文件,这个文件已经过时了,现在建议用unordered_hash.解决办法,在configure里面找到DEF定义,加入-Wobsolete 来抑制这个警告就可以了。然后重新configure 和make。
2: strcmp未申明
这个问题很容易解决,在公共包含的.h文件里面引入#include
3:类函数 Node:xxxx:
在很多.c文件里面,出现了static的类函数前面加上类名字。比如Node 类里面的abc函数是Node::abc(),我不知道这是那门子C++方言。反正在4的版本中g++不允许了。把这些类名去掉就好了。
4:代码错误 vividi
在vividtest.c里面vividitest类里面,有个半吊子成员量定义,用的类型是vividi,从来没被用过,看来是作者的低级错误。注释掉就好了。
6:bighashmap.cc include问题:
这个问题很混蛋,在ld做连接的时候,出现HashMap<>:xxxx()找不到的错误。HashMap是在bighashmap.cc里面声明的,被include在node.c里面了,但是其他地方都没有include. 作者的原意是把模板当作普通类,希望在node.o里面包括,然后连接到其他的.o里面去。真是疯了:C++的模板是源代码级别的展开,根本不可能这么搞的。我改成在所有公共的.h头文件里面包括这个cc文件。
2009年10月13日星期二
Back track 和slax
2009年9月18日星期五
WINTEL的阳谋
看一下现状,微软带领的window阵营一直引领着软件开发质量和性能越来越差,而软件体积越来越庞大的的趋势。从Windows操作系统平台,到Office 系统, 软件的体积都在以成倍的速度增长。到目前,我们的系统安装已经无法用CD介质来满足。新出的Vista和我们当前在使用的Office 2003或者2007,都不得不使用DVD光盘来安装。或者在我们所买的品牌机上,需要永久占据5G到10G的硬盘空间。
但是,我们所得到的软件质量是不是更高了?不是的,随着软件体积的庞大,以及微软为了更快的引入新的功能保持对软件业的领导地位,软件质量和性能远远不如以前。原来只需要几十兆的软件系统,现状以及增长到几个G的大小。然而这并不是因为带来了相同数量级增长的新的功能,而是为了加快开发进度抢占市场而忽视了性能和稳定性。包括微软在内,大多数的软件现状都是补丁盖补丁。如果你买一个软件,一年以内不打个3个补丁的情况是不可能的。看一下ActiveX和Dcom的设计,整体构架都低效率和不稳定。以一个日常的例子而言,如果用Word打开一个文档出现错误,所有打开文档的独立Word窗口都会崩溃。为什么? 因为所有的word都基于同一个DCOM组件。再一个例子就是DirectShow视频播放框架。无论在开发中如何小心翼翼,都没法避免最终程序的莫名其妙崩溃。原因也是一样,用组件搭成的软件,就好像用积木搭成的皇宫一样,随便抽掉一块就会倒。而这些组件的质量因为要求快速开发而大多低劣。即便是微软自己开发的组件,都无法保证在自己的操作系统上可靠运行。
那么当下这种情况的获益人是谁? 微软和Intel。 软件做的越大运行越慢,就需要更高的硬件配置来运行,Intel就财源不断。软件只求开发速度不求性能和质量,又帮助微软遥遥领先其他对手,必死对手。此外质量的低劣又为微软卖完win32卖98,买了98卖2000,卖了2000卖xp提高了源源不断的财源。每次升级,付出的至少是50%的支出(软件升级安装),或者100%以上的支出(购买新版本软件)。那么从98到vista,我们的确获得了5.06倍(以升级安装50%的额外支出为例)或者16倍(以全新安装为例)的功能和性能的提升?肯定没有,而且我们还得在硬件投资上加倍投资。
我所说的这些,并不是说技术的发展不重要。人类的确需要更高的科技来提升生活质量和环境质量。比如减少计算机的功耗,提高计算性能,降低计算机的寿命和报废后的环境影响,这些都是需要科技的进步。 但是更应该提高软件的性能和质量。WinTel的这种把戏,只是在以科技进步为借口,在讹诈计算机的消费者,实质是制造一个消费的巨大黑洞。
2009年7月9日星期四
JabRef: BibTex数据库整理软件
环保,绿色,高效的firefox插件:adblock plus
2009年7月7日星期二
TeXnicCenter 使用笔记
TeXnicCenter是Windows下最好的开源免费Latex IDE。但是从2008年底推出1.0stable版本后就一直停滞不再推新版本
笔记
(1)使用IEEEtran模板中关于bibTex的问题
在TeXnicCenter中在使用Michael Shell提供的IEEEtran模板撰写IEEE会议文章的时候,会出现bibTex错误。
错误重现:
所用的TeXnicCenter版本是1.0_r1 stable,新建一个空project后,在主tex文件里面复制会议模板bare_conf.tex内容,能够正确编译生成pdf. 但是如果把参考文献部分改成:
\bibliographystyle{IEEEtran}
\bibliography{paper}
则编译出错且无法生成PDF文件。查看编译输出,原因为IEEEtran.bst会生成一个不含任何item的参考文献列表脚本(.bbl文件). 使得Latex编译出现语法错误。如果在bib数据库文件里面加入参考,则IEEEtran.bst仍然拒绝生成,理由是tex对于的aux文件里面没有\cite{}命令,所以他认为它不必编译生成参考文献条目。此后即便在tex里面加了\cite{}引用,仍然同样出错。出错在于TeXnicCenter的编译顺序安排有问题(因为lyx就没任何错误)。
解决步骤:
1. 先加入.bib文件的内容;
2. 在.tex文件里面加入对应的\cite{}
3. 对.tex文件进行编译,不怕出错,只要生成.aux文件就可以
4. 对.bib文件单独run一次BibTex, 这次BibTex不出错了
5. 对.tex进行build, build 通过,完成。
后继的一些错误及其解决:
此后如果对.bib有修改和在.tex里面修改和添加\cite{},build的时候经常出现error 和 warning。也是同样的原因,但是多build几次,这些提示就会消失(一般为3次)。不会再和一开始的时候那样顽固了。
(2)不能使用独立子目录的问题
TeXnicCenter的编译不支持子目录,例如在处理BibTex. 在上面的例子里面,BibTex需要对.bib文件进行独立编译(run BibTex),但是会报错:找不到.bib文件所在目录下面的aux文件。似乎没有办法修改BibTex的设置,所以.bib文件只能和.tex放在同一个目录下面。
(3)工具栏布局丢失问题
TeXnicCenter经常出现丢失已经设置好的浮动工具栏布局,随机让工具栏重设:所有工具栏都重新一行,占据很大屏幕空间。目前没有办法解决。
2009年6月28日星期日
转载西西河: 如何写好科技论文的一些个人建议
笔者到现在为止在专业期刊中共发表过三十多篇peer review的学术论文,也曾经做过二十次左右的论文审稿人(reviewer)。根据自己的论文写作经验和审核经验,愿意将自己对如何写好科技学术论文 的不太成熟的看法及建议写出来与大家分享,也欢迎大家多多讨论以期共同提高科技论文写作水平。
发表peer review的学术论文,首先要过审核关。显然,如果了解审稿人在审稿过程中的侧重点,那么对我们自己文章的写作无疑是有帮助的。所以,不妨先谈谈我个人的一些审稿经历。
http://www.ccthere.com/article/1555183
在我审核过了文章中,仅仅有非常少量的文章我是认识文章作者的,不得不承认,如果我与文章的某个作者相识,那么我从来没有拒过他们的文章,这更大 的原因是因为我了解他们以前的工作,因此对他们的工作比较信任,另外个人感情因素也起一定作用。比如说,曾经审核过一篇文章,那篇文章的最后作者是与我私 人关系非常好,学术水平也非常高的教授,但是那篇文章写的质量非常差,甚至还有英文写作的问题,按平时的标准是应该拒的,但是只因为那个作者的名字在上 面,(我猜那多半是挂名作者,因为文章的写作风格完全不是那位教授的风格,那位教授既不是通信作者也不是第一二位作者),由于那家期刊(journal) 并不是很有名气,影响因子也不是很高,于是我再三考虑过后,决定给文章的整体评价是一般,然后写个非常具体的意见,建议编辑(editor)此文必须进行 大幅修改(major modification)以后才可发表,在论文修改建议中,我甚至给出了所需要的进一步分析计算的详细步骤。通过这个例子,我想说确实存在这种可能性: 如果你的文章中有比较有名望的教授挂名,你的文章的被接受的机会肯定会相对来说更大一些。
但是对于绝大多数我审核过的文章,我对作者根本就不认识,这时候我的审核标准还是比较统一的。一般说来,审核文章最主要的标准有三个.
http://www.ccthere.com/article/1555183
1,创新性(originality)
一般说来,编辑在找审稿人的时候(我自己也做过guest editor,所以了解这个过程),都是需要自己先浏览一下文章,然后找对领域比较熟悉的并且在领域内有点学术信誉(academic credit)的人审稿,这样就可以一定程度上保证对文章创新性的判断。越是名气大影响因子高的期刊越是强调文章的创新性这一点.影响因子很高的期刊由于 所收稿件比较多,编辑为了提高审核效率会第一时间直接拒绝那些明显质量不高,创新性不够的文章,而根本就不会把文章发给审稿人,省去了费力找合适审稿人的 麻烦.比若说,如果你的论文是有关实验的,那么你的文章中是否介绍了新的实验方法?你的文章是否发现了新的现象?还是更多重复或者遵从(follow)前 人的成果,仅仅对试验步骤作了些简单的修补?如果是后者的话,而编辑恰好又是同领域的专家,他们就很容易判断出来你的工作的创新性的,那么你的文章被直接 据掉也就不奇怪了。
http://www.ccthere.com/article/1555183
具体到我们的研究或者文章上,为了保证文章的创新性,我们做研究前一定要多做做学术文献检索工作(literature search),一定要搞清楚同领域内有哪些问题已经被解决,哪些问题有待解决;一定要找出那些比较重要的文献细读精读;一定要对领域内的专家最新动向有 所了解.而体现在写文章上就是,在写介绍部分(introduction)的时候,索引要写得清楚,全面。千万别小看文章的introduction,内 行看门道,如果你的文章introduction写得好,审稿人就马上能够判断出来你对领域的熟悉程度,他们对你的研究工作就会有一个比较好的第一印象, 审稿人的审核情绪也会有所提高,自然你的文章顺利通过审核的可能性也就大乐。
从我个人经验来说,我在写文章的时候,总是愿意先写正文介绍自己的工作,最后才写介绍(introduction)部分.而在任何可能情况下,我 的文章寄出去前,总喜欢找一位领域内名气大的学术水平高的老教授帮我修改introduction部分。特别是一般自己觉得比较不错的研究文章,在寄给杂 志之前,让同领域的“高人”帮你把把关不失为对自己负责对研究负责的好办法。
http://www.ccthere.com/article/1555183
文章的创新性(originality)当然还体现在文章主体关于研究方法的介绍,不过这里暂时不特别强调这一点。以后有机会单独开贴聊吧.
最后,我刚才提到比较好的期刊(journal)收入的文章,文章创新性(originality)是非常关键的一点.如果你觉得自己研究工作的 创新性不够,那么建议不要直接往顶级刊物上投。要知道投稿也是有学问的,因为如果你经常往某个杂志投稿结果经常被拒,你在那个杂志编辑心目中的学术信誉 (academic credit)就会很快丢失了.这样你下一次如果再想往同样刊物上发文章就更难了。相反你的文章被某个杂志发表的比较多,那么你也会慢慢也会积累起来你的 信誉,有了信誉没准那一天你会被期刊编辑邀请做期刊审稿人了呢.所以我个人主张发文章从选择合适的期刊(jouranl)开始就要慎重。同样的道理,被杂 志选为审稿人也是一样的道理,所以不要总听那些抱怨牢骚的话,不要文章一被拒就怀疑审稿人故意刁难,这种情况有但并不是主流,因为每个审稿人也需要考虑自 己的信誉.况且每篇文章不是一名审稿人说了算的,某位审稿人如果胡乱评文章,那几次以后他不仅没有机会再做审稿人,很可能他辛辛苦苦积累下来的学术信誉也 会丧失的。
http://www.ccthere.com/article/1555183
2,全面性(completeness)
如果文章有一定的创新性,那么第二个重要的判断指标就是文章的全面性(completeness)。这一点比较tricky。我审核过的文章,还 有我自己发表的文章被审核,reviewer多数是在此方面“做文章”。再严谨的研究者也可能会遗漏些自己没考虑到的地方,这时候,reviewer会指 出研究的不足之处,给作者建议让他补充新数据或者对某些结论增加些解释等等,最终reviewer给文章的评语多半是major modification,这种情况对试验和计算方面的研究更常见。也有些情况,文章不足的地方太多,甚至由于不够严谨导致结论“错误”,这时候文章多半 是要被拒的。
http://www.ccthere.com/article/1555183
在你从期刊编辑那里收到所投文章的reviewer comments的时候,一定要仔细查验那些建议或者意见。也确实会有些审稿人不负责任,甚至有可能他们都没有读明白你的文章,给出了比较荒唐 (ridiculous)的评语或者建议,但不管怎样,还是应该多在自己身上找毛病.仔细想想是不是自己文章本身实在是不够严谨,甚至研究中有太多的不确 定因素(uncertainty)?在修改文章时候,一定要认真考虑审稿人的建议并补充新的证明材料.如果文章被拒不要抱怨审稿人吹毛求疵,以我的经验审 稿人不大有可能是因为作者名气不足而故意刁难作者。但是倒是有可能审稿人对于他们自己熟悉的作者的文章尽量多挑毛病,避免直接拒掉,这可能是那些有名望的 教授发文章过程中能够占到的唯一一点"小便宜"了。
但是另一方面,大多数有名望的教授往往更看重自己的名誉,至少我认识的几位美国著名教授(院士),只要文章中有他的名字,在文章投出去之前,他们 都要自己最后亲自审核文章的。他们的审核甚至比通常的审稿人更要严格,而他们修改过的文章,不得不承认文章确实水平高,那么如果你觉得自己的研究确实不 错,如果能找有名望的教授愿意帮你把把关是保证你文章质量的不错的办法。
http://www.ccthere.com/article/1555183
3。写作技巧(writing)
科技论文的写作技巧并不像小说那样要求高。但好的科技论文是可读性很强的,关于科技论文写作技巧,以后有时间会单独开贴于大家探讨.这里有个联结链接出处,大家可以先看看,文章的作者是剑桥大学资深教授,学术水平很高,都是他的宝贵经验,对于我们这种刚开始写科技论文的新手来说借鉴一下绝对有好处。
http://www.ccthere.com/article/1555183
另外,我们千万不要忽视科技论文的写作技巧.因为文章写作技巧对文章的发表与否,和文章发表后的引用情况都有影响。在文章审核阶段,审稿人在审核 文章的时候,如果作者经常出现语法错误,那么几乎是他们最难以忍受的,这表明作者对文章的写作态度就不太端正.给审稿人的印象会非常差,这种情况下审稿人 会对文章的审核更吹毛求疵一些也就不足为奇了。另外,写得比较好的文章,可读性强的文章,在文章发表后能够引起更多数人的注意,相对来说影响力 (impact)也会更大,文章被索引次数当然就会更高。所以在发表文章前最好多修改几遍文章,哪怕是找别人帮助看看语法对自己文章质量的提高也是有帮助 的。
最后,希望大家要正确对待论文被拒.在我个人发表的文章中,就曾经有一篇被拒过.我为了那篇文章前后狠下功夫地做了一年左右的研究工作,当时被拒 觉得很不公平,但是过后想想却觉得"因祸得福".我当时是这样做的,那篇文章被拒后我等了半年多才第二次发表出去,期间又进行了大量进一步的研究,并对原 文进行了大量的修改。结果那篇修改过的文章现在成了我所有文章中被引用次数最多的一篇,几年时间内已经被引用超过百次.所以说,文章被拒的经历并不见得是 坏事,态度端正以后,会把坏事变成好事的,用米卢的帽子上话来说就是“态度决定一切”。
2009年6月2日星期二
解决了wanda小鱼的中文乱码问题
cd /usr/share/games/fortunes/
sudo sed -ie 's/[[:cntrl:]]\|\[33m\|\[32m\|\[35m\|\[m//g' tang300
sudo sed -ie 's/[[:cntrl:]]\|\[33m\|\[32m\|\[35m\|\[m//g' song100
sudo strfile song100
sudo strfile tang300
用上述命令的时候记得检查单引号,千万别用中文的单引号,不然就报错。
Debian下用iceweasel编写hotmail邮件的问题
2009年6月1日星期一
软件的艺术化
2009年4月27日星期一
Scilab 5.1.1使用感受
2009年4月24日星期五
终于等到了scilab 5.1.1
scilab出了5.1.1版本,让我等了3个多月。应该说scilab从4.1到5.0的升级太让我失望了。首先是体积大了好几倍。4.1才25M,5.0就长到了80多M。但是比比matlab,也没什么好说的,还是苗条太多了。其次,4.1版本的断点设置和调试功能在5.0里面都被去掉了,程序只能靠经验和猜来调试了。这个是最垃圾的升级了。其次就是不稳定,我的程序需要占用较大的内存,run一次没问题,再跑一次就出现栈溢出了。这个错误实在是太低级了。 但是到了5.1.1版本,发现稳定性的问题终于解决了。5.1.1还有一个比较好的地方,就是提供了stacksize('max')函数,可以让scilab尽可能大的利用系统的内存资源。这点比matlab都好。Matlab中反正我没找到这方面的设置。
2009年4月21日星期二
GnuPG在windows下面的问题
2009年4月20日星期一
2009年4月19日星期日
BT都带后门了
如果不是这次出现了意外断网,我根本不可能发现这个问题。在屏幕的背后,真的不知道有多少恶意的程序在我的电脑上。当大家越来越依赖网络的时候,大家越来越失去隐私和安全。