wpe7.jpg (11495 bytes)

我的征尘是星辰大海。。。
The dirt and dust from my pilgrimage forms oceans of stars...

-------当记忆的篇章变得零碎,当追忆的图片变得模糊,我们只能求助于数字存储的永恒的回忆,

                                                                                                        作者:黄教授

                                                                    二零零

一月四日  天气不算坏,大街上的霓虹灯显示着零下4度

早上去参加所谓的citizenship的考试,再过一个月就算是这个国家的正式公民了,只欠吃饭时候浏览的那些垃圾中文报纸里有一篇文章也是写公民考试,题目是《归顺》,一幅酸溜溜的仿佛天朝大国的臣民跑到从前的附属国当二等公民的心情一样,真是典型的阿Q精神,入乡为何还不随俗,当“白雪枫叶”国家的子民有什么亏待的呢?虽然是穷困潦倒可也算是生活在the most fertile country in the world,这是我在考试完后等待的时候看到的宣传移民的广告上的口号。

去年的这个时候,当我犹豫不决地想着我的年终总结的时候曾经总结出所谓的国际惯例中的那个“惯”字既是习惯的“惯”字,也是惯性的“惯”字,也就是说一件制度的形成往往如这样习惯成自然,从一开始的偶一为之到后来的一发而不可收拾,不过,中间必须经历过一个能否持久地考验期,但愿一个好的习惯能够在朋友的监督下不至于太快地夭折,那么本周么完成,如何?(现在在报告的截止日开始写作似乎成了我最近养成的坏习惯,虽然这也是入乡随俗的一种表现。)

每当我在忙得不亦乐乎的时候总是期待着将来有一段完整的空闲时间来做很多我想做而做不了的事,可是当这个时刻来临的时候我在干什么呢?天知道过去的十几天我是怎么生活的?洗澡的时候想起了从前听说过的希腊神话“奥德赛”,其中希腊英雄乘船返家的时候路过海妖的岛屿,俄底修斯知道没有人能够抵御海妖得歌声就让水手们都塞住耳朵,并把他绑在桅杆上,这样虽然海妖得歌声是那样的令人抗拒航船照样向前驶去,我想连半人半神的希腊英雄也无法抵御一些世俗的诱惑,世上基本上没有什么人能靠个人的毅力坚持自己的信念很多年吧?也许那些真正执着的人都有一些束缚防止自己觅食灵魂吧?

一月五日  又是大雪纷飞的日子

早上去买书又花了两百多刀,心里很有点心疼的意思,不时心疼钱而是心疼自己万一又没有读书才让人心疼。冬季的学期我的运气总是比秋天要好,好比苏联红军总是在夏秋防御而在冬季反共吧。想起了我对于java的一窍不通好比《围城》里说的学旧体诗的干预说自己不懂新体诗,而学写新诗的决不敢说自己看不懂旧体诗,学c++的人总是敢于盛气凌人地宣布说自己不懂java,或者不屑一顾地说我不学,而学java的似乎不太敢这么反过来说,因为java实在是傻瓜化的多余了一点,当然我试着装了一下visual2005也是一样地感觉,程序惊人的庞大笨拙,我得可怜的机器几乎停止了,没办法只有卸载。

一月九日  又是又是大雪纷飞的日子

去年的总结是迟到的,今年的也许该说无可奈何的了

有同学来要AI的资料,让我又勾起了一段伤感,本来都已打算盖棺定论的句号又被临时改成了逗号,不,实际上是顿号,因为仅仅是短暂的停顿而已,并不会从此变成惊叹号,当然在外人看来这一切不过是遗传的问号,明天再结束的军号后面再添加两个中国式的军号就变成了尽在不言中的省略号。。。

晚上终于下决心把去年的衣服全部送到洗衣房去清洗,当然最主要的原因是一个下午的“学生骑士团”浪费了无数的光阴,强迫自己去洗衣房看“组合算法”。这门课看了个开头却总有相见恨晚的感觉,从前我曾经苦思冥想过的种种问题其实都在这其中,甚至我念兹在兹的窝自己眼中的AI的问题也都在这里面可以找到答案。然而我又有些困惑,照教授和作者的说法这方面早就是计算机界的经典领域,自从上个世纪70年代后就已经有了定论,据说此方面的书甚至都只有那以前出版的。我曾经看到一种评论说,天才Erdos所感兴趣的大部分问题都是这个领域的,据说其中很多是死算机科学的奠基石,或许大师把后人的工作都干完了。

《Blade Runner》究竟有多少种结局呢?这部电影是我个人认为的最经典的几部科幻片之一,其成功之处在于电影的音乐与画面,在没有CG制作的时代这个是绝对的经典,其中更有一些时代的痕迹时非常有意思的,那时日本正是如日中天的鼎盛,打油买下整个美利坚的气概,影片中处处露出美国人那种不满又无奈的心情,洛杉矶成了东方人的天下,到处是象形文字的广告和标识牌。

《The Island》(逃出克隆岛)可以说是带着深深的DreamWork的制作痕迹,这几年他做的一系列科幻片几乎如出一辙,《Pay Check》,《Minority Report》,《A.I.》。。。甚至在很多特技上你都可以看到相似的影子,题材的住址(theme)大都是一个:科学进步的成果如果被滥用会怎样?当然西方社会的科幻片绝大多数都是阴暗的调子,充满了对未来的恐惧,《The Day After Tomorrow》,《Water World》看到了人类对气候的影响导致灾难的降临,《The Time Machine》里面反映了人类对自然规律干预所带来的backlash,在六七十年代对于宇宙飞行的热情消退以后,科幻片似乎成了灾难片的代名词了。

一月十日  又是又是大雪纷飞的日子

我想去桂林

组合算法的书实在是比较的艰深,看起来几乎是逐行的证明,当然比起数理逻辑的通篇符号推导还是容易得多,那种书我在图书馆看到几乎都是剑桥的天才写的,这方面还是老牌名校强过美国的名校,因为美国主要是有大公司在背后撑着。好像一个小时就看了三四页。

我整天都在用电驴下载电影,它的图标很有意思,就是一直蒙着眼睛的懒驴。俄底修斯如果没有被绑在桅杆上是过不了海妖统治的海域的,人如果不像驴子一样被蒙住眼睛在这个五色使人目眩,五音使人乱耳的世界里是不可能拉磨的。

在所有的007系列里面我只喜欢一部《The Living Daylight》(黎明杀机),罗杰姆尔太过于老态龙钟,虽然是一个英国绅士的派头,却和间谍的身份不符,皮尔斯虽然有相貌有气质,却过分英俊了些,表演的成份太多,因为间谍的相貌首先是大众化的脸谱,只有提摩西达尔顿让我觉得合适,同时这部戏构思完备,跌宕起伏又不失真实,再加上其中的主线是反对当时前苏联入侵阿富汗的正义之举,因此无论艺术性还是思想性都远在其他剧集之上。当然我在大学的时候喜欢那个女演员,就是那个拉大提琴的莫斯科音乐学院的女学生,多年之后才知道她的名字叫做玛利雅德堡。

下午看大决战很受鼓舞,指挥员的决心和毅力往往是战役胜利的保障,于是下定决心从今天开始每天晚上去图书馆看两个小时的书,就算是在那里睡觉心里也比较踏实。晚上看了一个半小时的书睡着了两次,这本分布式计算设计的书实在是空洞,至少开头部分都是写在纸前网络那门课里面学过的,到最后十分钟才看到比较有趣的RPC,感觉和我那个时候在“正航”做得那种DCOM没有什么区别。回来的路上想到当时教网络的老师,至今我仍然心存感激,在这所名不见经传的三流大学里我还是着实地学到了一点点皮毛的,其中有很多教授都是那样的诲人不倦严谨认真。不小心又看到两个小留学生,门面全部用白粉刷过一遍,妖冶的好似Van Helsing里面吸血鬼的情妇一样。:)

一月十一日  不是大雪纷飞的日子

做了一个很奇怪的梦,忽然糊里糊涂地进了城堡,一个完全陌生的城堡,城堡的主人根本没有见过,也根本没有怎么说过话。看到Java里面的所谓BufferedReader期限完全不理解为什么要这么多此一举看了两三遍说明才恍然大悟原来就是类似于C Language里面的library中fgetc的意思,这个东西在学comp444时候最有体会,还自己写过,这样看来Java也不都是傻子,这样的包裹方式也还是挺有意思的。

一月十五日  终于迎来了严厉的天气

来到加拿大才知道写报告的重要性,似乎中国的大学很不重视这方面,结果我总是在这方面吃大亏,前天comp495的报告差一点就被否定了,因为我那根本就不像是报告,简直是一个小小的summary。反观这里的同学写报告无不非常认真,各是有其重要,而且不管怎样一定要加上一些图标,table index, figure index也很重要。今天被小皱交到实验室学习,还是有一些小小的收获的,有一段时间没有玩c++,编程的时候有些翻来覆去的,想法多了路子多了,考虑得多了,反而变得慢了。以前不知道怎样定义一个数组类型,现在也知道,其实和函数指针类型的定义很像:typedef  unsigned int Set[20]; 以前不知道什么时候留下的概念一直认为short是8个bit,真是好笑,今天才发现是16bits。

一月十六日  天气变得更加严厉

今天冒着严寒去银行把政府退给咱的几块钱存到户头,毕竟对我这样的人来说钱是非常非常重要的,顺便去实验室下载安装MPI/LAM,我实在是搞不懂是否我可以在任何一台服务器上使用MPI?并行处理对我来说好像是天方夜谭,cluster对我而言是圆的还是方的?当然也明白了一个很幼稚的问题,学校服务器上面有一个文件服务器叫做www,在上面的文件时可以webpublishing的,我以前一直以为只有alcor才是唯一可以网络发布的,看来对于网络来说我的知识比普通专业的多不了多少,努力学习吧。为了使自己振作起来,我决定去健身房办一张卡,毕竟一个月40块钱的YMCA会员的消费超过了我的经济能力了。昨天,杨大虾给我讲了一些东西,只觉得非常的清楚,但事后好像忘了很多,什么MPMS,SPMD,SIMD。。。我对这些还是非常的陌生,看看MPI的接口说明感觉很多都好像是同步的东西。handle,communicator从那个函数获得呢?不对称的网络是不是也可以使用MPI呢?PVM是什么碗糕?我现在记忆力下降的速度几乎是exponential,因此把我要做的是倾泻下来吧,我准备这个学期学会emacs或者vi中的一种。(这样的雄心壮志要被所有计算机系的学生笑掉大牙的。但是我确实不会,只会用pico或者nano。)

晚上去图书馆看书的计划只实行了一天,我现在几乎就是hopeless了,那么今天晚上在坚持一天吧。

一月十八日  天气阴沉沉的

学校图书馆的书借了很久都没有看过,书非借不能读也的借字不是从图书馆借的。今天翻了一下design pattern,因为杨大虾说OOP有三种境界,class-->pattern-->??我忘了,反正我现在还是在第一层或者一二层之间也不用关心最高层是什么了。我对于这一类极高的抽象的东东的看法是你绝对不可能跳跃式的学习,不要以为最高层的武功威力最大就从一开始就学最高层的武功,实际上武功都是连贯的,你没有钱一层的基础根本不可能理解上一层的设计,否则只是纸上谈兵是的卖弄名词,这类人可能你每天都能遇到很多,口若悬河实际并不知道怎么去做。我的体会是那些pattern也不是什么天上掉下来的不过是些代码写多了总结出来的,而它的真正意义是在于一种程序员之间的共识,大家能够很快地交流,也就是说有了共同语言可以一点就通,所以这本书说实际上有时候设计这些pattern的名字是一件更难的事情(这也许是我杜撰的,我是这么认为的,携带马的时候我在给方法其名字上画的时间非常的多,有时候为了把心爱名字保留给最合适的方法费了不少心机,也许学过软件工程的知道团队必须有共识,共同的语言,大家有共同的vision,对我个人也是一样,一个月以后我回头看我的代码我感觉如果是看别人的一样那就是失败,但是如果名字起得好,我很多时候甚至重写一遍都写得差不多。)不过,闹笑话的是我看到那些pattern以后很高兴,就拼命去找有没有源代码,后来google了一下觉得我还是没有理解真谛:framework是一个设计好的架构,是别人想好了方法名字流程,数据流,你自己往里面实现具体的代码,当然你是可以找到这个源码的。可是pattern仅仅是一个设计思想,超越了framework你怎么需要真正的源代码呢,他仅仅是一种设计思想,你可以找到范例但是你绝不应该有现成的源代码呀!否则不就成了library了吗?书上说的library和framework的比较很生动,library是更侧重code-reuse这方面,它是尽量地不涉及设计部分,而是一些最基本子常用的底层方法的实现,应该有着最少的assumption从而有着最广泛的重用性。这正好跟framework相对,因为framework是设计好的架构却没有具体的实现,一边又最大限度的设计重用性。写到这里我突然想起来了三种境界是:class-->framework-->pattern,总之我大概就刚从class浮上来的途中吧。但是并不能说这三个东西是迥然分离的,实际上人的思想从来不可能绝对地停留在一个层次,这些最高级的抽象是低级实践的总结,比如classfactory的想法我很早就实践过,那个时候想写一个深度搜索的“套路”,(DFS)就写了一个框架,因为DFS和DFA很像,无非是定义出所有的搜索选项,以及目标条件,然后或者用递归或者用循环去搜索,并输出结果,当时不想把类的名字写死(hardcoding),就用一个指针代替,让后来的人自己定义产生类的方法,当然你可说这是纯粹的继承,但是本身pattern就是一种设计思想,具体用什么实现方法并没有限制啊,也就是实现的设计。不知道这样总结pattern是否正确。

顺便说一下,小时候看的电影《未来世界》之前确实有一部《西部世界》。现在看六七十年代人们对未来的想像很有意思,你可以比较一下那些人们预见的是对的,哪些到现在也还是幻想。

一月二十日  天气暖和的不得了

新闻上说莫斯科遇到几十年不遇的严寒,蒙特利尔确实我来的这几年里最暖和的一个冬天,简直和厦门的冬天感觉一样,下午单单看着那明媚的阳光如果没有注意到地面上的积雪那就是厦门的气候了。整天在下载《古钿任三郎》来看,感觉很是心驰神往。

另外下载了一个<TLS>的另一个结局,是一个皆大欢喜的结尾,两个主人公各自有了新的生活,不过总是觉得还是原本悲剧式的结局更加得艺术化一些,所有的问题都不作解答,观众可以做任何的猜测想像,而这个另类的结局仿佛为了满足观众的好奇心与怜悯心所做的一个安慰剂。一个由这三个句点组成的省略号被导演进行了一番挖掘演绎,一个变成了问号,一个紧接着的惊叹号,其间穿插了若干个逗号,顿号,在一系列的似曾相识的引号过后,(都是一些可能在那里看到过的吧)突然一个破折号引出了一个大大的句号。仿佛两颗原本在各自不想干的轨道上运行的行星在一个偶然而又必然的时间地点不期而遇,在即将擦肩而过的瞬间彼此因为对方的万有引力而被吸引,在俘获对方的同时也被对方俘获,从此变更的轨道在继续近似原本的公转轨道的同时还成为彼此的卫星,在互相的卫星式的旋转的同时多多少少保持原来所剩无几的自转。然而这种混合轨道的旋转的不稳定性导致终于有一天彼此卫星式的旋转的离心力大于彼此间的向心力,其中一个卫星不知是因为原本的惯性还是因为另一颗恰好路过的行星的吸引力脱离了这个不稳定的系统,结局大约有这么一些可能性:1。两颗脱轨的行星彼此都和另外的新的行星组成了一个相对稳定的卫星-行星子系统;2。其中一颗与其他行星组成了新的卫星-行星子系统,另一颗恢复到了最初的轨道继续无休止的绕太阳公转;3。两颗脱轨的行星都恢复到了当初的轨道期待着下一次的捕获与被捕获;我们现在看到的<TLS>的结局应该是第二种,男主人公组成了一个稳定系统,女主人公留下了很多的未知数,然后突然在消失了三年后,三颗行星在大街上相遇了,在短暂的重逢中并没有回答女主人公的结局是什么,一般的猜测是至少目前还是在公转中,然后片尾音乐结束了故事。我看到的下载的这个结局是近似于第一种情况,主要是花了半集的篇幅交待女主人公怎样自觉自愿地重新被另一遇到的行星捕获与被捕获,悬念没有了,味道也淡了很多。大凡情理之中意料之外的事情是本有可能性,智者察之,因势利导之,于无声处听惊雷。

今天吃多了就去了健身房,资本主义残骸劳动人民的办法就是让你穷得顿顿只能吃肉,好像养猪场的饲养员一样的残忍,不要以为我是在说笑话,你只要看看这里的中国人总是买那些特价的食品就知道这实际上等同于用最少的饲料喂肥一头猪一样的功利主义。我不想成为这样的受害者,因此我决定少吃或者不吃。就好像为了避免死读书而拒绝读书一样。

Unique factorial representation.

一月二十三日  天有些阴郁

《古钿任三郎》似乎也走到了它的尽头,那个经典的谜题被揭开:对面走过来一个男人头顶上还顶着一个红脸盆。这是什么意思?我想绝大多数人都猜不出来是什么意思,因为这是一个应该为大多数人所熟悉的问题,那个男人一边小心地循规蹈矩地走着一边又要小心翼翼不让两盆里的水洒出来,为什么不把脸盆放下走路呢?这个红脸盆是编剧手中的《古钿任三郎》,是大多数男人手里的未完成的事业,是不可能放下的,因此虽然编剧也许觉得无法在继续,在观众的要求下,应该也会再次向福尔摩斯的《归来篇》一样让这个侦探复活的。

我的中文名字被google特异地删除了,真不知道这是一种特别的轻蔑的抬举还是一种技术上的垃圾清除,总之,我觉得非常的不可理解,搜索引擎会这么无聊吗?也许他觉得我无聊吧?不过,我再次简单验证了一下,情况是这样的,google是按照这个人的社会地位来决定搜索的人名是否应该被留在索引中,比如我妹妹和我都没有资格上索引,我爸爸就可以,这就是google的商业策略。

晚上玩了一小会儿MPI,感觉不会比socket programming更难,当然这是因为别人作何太多的工作,我只是当了一回傻瓜罢了。如果没法运行,mpiboot,编译mpicc -o target source,运行mpirun -np number exe,本机运行mpirun C exe。我猜想是不是每台机器上都是有这么一个daemon在运行,否则你怎样启动远程的机器呢?

GrayCode a与integer b的转化可以这样a=b^(b<<1);  b=for(int i=1; i<sizeof(int); i++)a^=(b<<i);

下午去实验室睡了一觉很满足的,主要是一个同学要我去给他一点帮助,否则我才懒得去实验室呢。顺便把latin-square的搜索改了一下,也就是说所有的搜索问题都是这样:一个按一定顺序产生所有元素的机制,一个用以检验所有产生的元素的判断机制,其中可以作适当的优化,比如快速跳过不合格的元素的机制,那么你就可以在判断的函数中输出你的结果,这个中心思想就是线形的bruteforce搜索,关键是怎样产生所有的元素的方法。Combinatorial Algorithms可能是我寻找了许久的方向吧,事实上计算机最基本的binary representation里的two's complement, one's complement等等都是来源于这个领域,自然数的表达的本质也是来源于此,可以说就是按照什么顺序排列subset的问题。这个pattern够不够普遍了?!!!

我今天把头剃了,希望头发短一点,见识能够长一点。现在总是振作不起来,比起从前的想得比说得多,说得比做得多还不如,现在干脆不想也不说,更不做,每天活得比猪还幸福。

一月二十六日  天好像下雪了

让C++程序员来写java需要多长时间来学习?我想需要至少四个小时的学习吧?(夸张了吧,前提是你对java一窍不通。)但是有些东西可要小心不然你会怎么也想不出来的。一个class一个文件,package是目录名,import=include不过要换成package,所有的变量名都没有分配内存,java里面没有静态变量,因此,C++程序员总是会忘记用new给变量初始化,constructor你要老老实实地加上空挂号即使没有参数,所有的方法都封装在了一个一个类里面了,因此你要证书转字符Integer.toString(int),在windows里面最好设定环境变量为classpath=你的工作目录,在java里面exception如果忘记catch编译器不会放过你,这一点倒是比较好,C++的const被换成了final,你想要用传出参数int&,对不起primitive type都是传值,你只能用对象,不过在RMI里面的参数你必须要用实现了Serializable interface的类,我因为不知道这个照实地迷惑了半个小时,后来打电话问了两位大虾才有了一个眉目,本想自己去实现,稍微读了一下sun的介绍就赶紧放弃了,没有想象的那么简单,还是用String代替吧。总之,用一句从加拿大学生那里学到的英语就是java sucks。

一月二十八日  天晴了,不下雪了,晒衣服吧

昨天在实验室里耐着性子折腾了一下午,最后发现RMI很傻的,根本没有办法做到remote transparent,而我已开始天真地以为可以在RMI参数里面传引用以便作为传出参数,实际上这是有前提的,第一是一个RemoteObject以便在远程建立一个stub,然后。。。我当时没有写下来现在就全忘了。

一月三十日  天好像又下雪了

不知道为什么心情总是有些沮丧,半夜里从梦中惊醒居然是自己成了电视剧的主角,而那个OL似曾相识,然后开始怀疑自己的记忆,究竟作业的deadling是不是昨天,慌慌张张地提交之后在确认自己是杞人忧天。想起了rmi的registry不仅有些感慨,随便有个名字就可以bind,居然可以把这么复杂的通讯任务简化到只靠媒妁之言的地步,而DCOM里还要用一个唯一可识别的guid,bind 的随意当然也就导致了可以非常容易的rebind,unbind,而且sun.com上说得即便getRegistery了也不代表远程的success,你还是要进一步的验证。

想到和supervisor的appointment,就开始为那些个不可能的任务辗转反侧,仿佛要重新设计新的programming paradigm一般,distributed&parallel是这样的复杂,你却还要在这复杂之上拨云见日理出头绪定下规则,这简直比对没有任何可预测性的人性进行预测规范还要难上加难,因为一件工作如果是绝对不可能,那么反而是一件最简单的任务,反倒是看似不可能实际上又有一丝可能性的任务才是难上加难,因为你不能说不能,可是真的去做实际上比不可能还不可能,人力总是有所不足。昨天一直想把作业贴上,说起来也许没有多少编程的量,可是毕竟是第一次用java些个像样的东西,以前唯一接触过这个语言的是老师给的code,让你填空找错,当然那个也不容易因为是多线程的东东。鉴于是第一次学习一门新的语言,给一颗星星以资鼓励,总的来说也不能说很简单毕竟是用rmi实现一个client-server,自己写一个toy的象征性的database,也考虑一些synchronization的问题,因为rmi是可以multi-thread的,我当时对于java的众多的static method是否thread-safe问题总是将信将疑,得到的信息也有些不一致,当然最后我还是倾向于tutor的意见,只要sun的程序员不是白痴就应该保证这些static method绝对不会用到global variable,那么temporary variable是存在每个thread的自己的独立的stack里的,虽然众多的thread共享一个static method,但只是共享一个code or text of code,没有data,这都是些只读的东西,每个thread仅仅维持一个instruction pointer指向某一个instruction,context switch回来还是一样,不会有什么问题,而我记忆中的Linux的library的没有thread-safe的tempfile,random number之类的函数是因为用到非temporary的变量,可以看作是global的

后来我猜想我的烦恼可能就是别人弃之如敝褛的我却求之而不得。

去学校实验室看到同学用JDBC通过ODBC连接数据库(Access),这里面有一个Java非常强大的东西,就是从class Class的forName方法动态获得类,这个东西好像delphi里面也有就是所有的类可以通过一个“元类”(meta class)来寻找和构造,只要你给出名字,这样像java这样的动态系统才做得到,是的动态链接变得无比的强大,因为这比接口还要广泛,当然比接口还要慢不知道多少,不过这些有一部分是我的想象,应该差不多吧。另外一个就是关于两个thread执行一个synchronized RPC等效于一个thread执行asynchronized RPC的问题,应该是让两个request金可能同时发出以便不让较快的server空等。

 杨大虾提到过的所谓reflexive,我现在也明白了,应该就是利用Class class的forName()方法去获得一个类的指针,然后再利用getInterface方法获得它所实现的接口吧?这个听上去好像是interface unknown的最基本的三个Interface之一啊,我当时实验的时候挺高兴,以为发现了什么新东东,一写下来才觉得这不就是所有接口原本就有的吗?COM里面支持vb的接口调用不就是这样的吗?这应该不算是所谓java所独有的吧?应该是别的什么的利用java动态执行其可以获得类型的特性,也就是RTTI(run-time-type-information)。

MPI看来是没有想象的容易,毕竟这种程序要比socket-programming难一些,因为是SPMD有很多地方的code要写成多个process运行的,虽然没有同步的问题,可是毕竟是远程的。要记住c++的编译器是mpic++。晚上在实验室通过了compilation,当然还有逻辑错误,不过我想溜到明后天吧,晚上回来觉得有些兴奋就写了一个用thread来测试mutual exclusive的测试,用到了一个CyclicBarrier的同步的东东。java好简单啊。

晚上睡不着只好爬起来看《King Arthur》,这部片子当时首映的时候去电影院看过,非常震撼,现在重温以便依然是那样的令人热血沸腾,片子中的女主角也是我喜欢的类型,典型的亚马逊女战士,善于使用弓箭和短兵刃,要知道在整个冷兵器时代英国的长弓是历史上最强的弓箭了,而罗马的重甲骑兵可能是也是最强的骑兵了,(帝国时代里面是拜占庭的骑士),阿瑟作为salvation knight的首领当然是最强的了。

二月一日  天好像不下雪了

晚上睡不着,早晨偏又起得早,爬起来把昨天调试一半的MPI的程序调试了一早上,看来我当初是夸了一点海口,说什么MPI比socket容易,其实虽然说没有同步等等烦人的东西,如果你要写成SPMD,也就是单个的程序,你一定要头脑清楚你的master,slave的区别,写惯了c/c++程序对于变量都很小气的,时常为了少一个变量而处心积虑地反复用,这实在是一个坏习惯,我也一直在改,想想看徐国编译原理的都知道对于c/c++这种静态编译的临时变量来说(函数内变量)都是些stack里的偏移量,除非说是很多循环根本谈不上什么资源浪费,而对于coding,debugging来说临时变量也好看的多,而最要命的就是我花了将近一个小时找到的错误正是我忘记了master/slave区别的地方,结果算法部分都是没有错的,我却始终怀疑,始终没有想到是最后文件输出的错误,(在远程的slave输出了一大堆文件没有报signal11的segment fault才奇怪呢),当然这里面也有一个主要原因是i/o总是滞后并且因为context-switch的关系顺序无规律才让我始终不知道是master还是slave的问题。以后应该明确n#就是指的那一个node的process出的问题。相比之下,java的程序员简直就是花花公子一样的浪费内存。

中午吃的多了,为了帮助消化屈尊到学校救济贫困办公室指出了他们工作人员在我的案子上的一些错误,他们表示政府会很快把上学期的钱给我了,回来的路上高兴的合不拢嘴,下个月的粮草终于又着落了,写完日记高兴地躺倒睡觉。

二月四日  天没有下雪,健身房星期六早上不开

MR.D写email来问combinatorial algorithm这门课好不好,我当时不知道应该怎样回答他,事后想来大致可以猜测他的想法,当我在学习另一门算法课的时候,我认识到了两件事,第一我没有学习算法的天分,被老师骂得都没有信心了;第二无论是什么样的复杂的算法问题也许最终都可以化简为最基本的组合算法,也就是enumeration, generation, searching of combinatorial objects。这个大胆的假设是我自己这么说的,我不指望别人来评判,反正这是我的想法,想想看我们的算法的基础数学实际上是可以完全用形式语言来表达的,而formal language和集合理论有着千丝万缕的联系,直觉上觉得本来就是一回事,比如说逻辑不过是一个集合理的一些特定子序列,(当然我只是这么模糊的感觉,就算是Intuition吧)那么当你为了一些非常非常需要效率的算法而苦恼的时候,你几乎一定会求助于组合算法。我想大多数的计算机的书都不会说所有的算法都来源于组合理论,及其组合算法,我想我不妨大胆地假设这个原因是因为这一类算法非常的抽象和普遍,对于特定问题有时候并不一定是最好的,因为大多数实际问题我们或多或少都有一些额外的信息可以利用来设计更有效率的算法,反而是最普遍的算法成了最没有用的算法,这几乎是计算机领域的大实话,好像很少有人这么说,至少写到纸上就要被大家笑话了,所以我就自己对自己说吧。可是如果你的问题是要去解决最普遍的问题是用于最普遍的领域,缺少最基本的假设,那么你的算法是不是只有组合算法可以用呢?我心中一直想像的这个问题就是意识的朦胧时刻,或者说《2001,A Space Odyssey》的开幕曲里面元人在连最基本的工具还没有发明出来的时候,the dawn of mankind。道可道,则非常道,名可名,则非常名;如果一个算法是基于某种pattern的话就失去了普遍性,然则没有pattern又怎么谈得上算法?java或者delphi里面都有class of class的概念,这其中的玄机有时候是非常的微妙,class可以依据名字让虚拟机在runtime找到产生,然则class Class本身是否也可以或者也许要用名字来产生呢?problem of chicken and egg的问题是能够让人疯狂的,当初关于set可否成为自己的元素的问题就让某些大虾疯掉了,我当然不敢去尝试。本来一直想去读那本国内买的影印版的《logic for mathematician》可是总是想的多做得少,也难怪那本书实在是艰深无比,我自己课本里的Turing的关于program不可知另一个program的证明都没有看懂,怎么可能看懂Godel的incomplete theorem?不过是怅惘一下罢了。

这几天过的乱七八糟的,主要是RMI的莫名其妙的问题,我偶然中运行了两个远程的server,结果我的server端的synchronization就变得一塌糊涂,marker的意见是应该是我的同步的code有问题,我前天测试盗版也似乎也是这样,但是我实在想不出我的semaphore有什么问题,也许我应该做一个简单的test case,我甚至一度怀疑学校lab用的NFS的问题。MPI的小作业也花了我一两天,主要已开始很畏惧这种cluster的程序,很小心翼翼翻来覆去地想,写完了还挺得意,后来和上过这门课的同学聊起来,发现居然连不会写程序的人都知道怎么写,让我很是沮丧,都不太想保存了,不过为了尊重历史还是贴上吧

我以为哲学是一门寻找和研究pattern的学科,形而上学有的时候是必要的,因为广义上说所有的pattern最终都可以找到自然界的应证,致使多寡早晚的问题,于是预先穿凿出的pattern虽然看起来脱离现实未必不是将来的时为普遍的现象,只不过不同时期的人类认识能力与手段的限制不能够意识到那些未发现的pattern。

有一天晚上碰到一个感叹号,一晚上的心情犹如波浪号,思绪万千好似破折号,然而那种冲动只是一个小小的顿号,两三天以后回想起来仿佛是引号,也就是说如同听别人的故事一般陌生。

二月七日  天好像有下过雪吧,至少现在没有

我想15puzzle也许可以尝试着用minimal change of permutation的想法,当然还有很大的一个gap。不过我的idea非常的simple,假如context可以有一个rank函数来linearize的话,搜索问题就可以分割,不过这好像是废话。今天尝试这个idea,去在breca上把generating subset in the order of Gray Code的工作分到11个cluster上,(master不做运算)分的方法非常简单,用rank产生那个subset,然后next一定的次数,master汇总所有slave的时间,这个尝试当然没有什么意义,不过,第一,我尝试着把code写的fancy一点,以便好像学EE的人,结果不得了,&,^,|的操作负的precedence竟然比==,!=等等的逻辑操作负低,结果就出现了一大堆的想不通,比如if (a&(a>>i)!=0)。以后还是写的kiss一些吧,(keep it simple and stupid)第二,cluster单台的计算能力就已经超过了我的想像力,难怪要150k加币呢。气愤之余偷偷地把我以前写的15puzzle放上去run一run,不用白不用。

二月八日  天灰灰的

早上决定去健身房,既然头脑不打算工作,身体就运动吧。8puzzle的事情变味道了,我想去做个试验。

二月十一日  下午的阳光是那么的灿烂,可我还得要去实验室镇是难受

奋战了一个下午也没有把namingcontext搞定,这里就看出java的丑陋之处,明明就是需要指针的地方用了一大堆的看的莫名其妙的东西搞得我晕,namecomponent是个什么东西啊?看上去像是STL里的map一样,总是出错,后来晚上又去才发现了我的错误,binding字串和binding对象是不一样的,比如邦定对象是这样的:NameComponent path[] = bankContext.to_name("Branch"+branchNo);  ncRef.rebind(path, bank);你生成的namecomponent的数组是靠namingcontext的借口方法to_name实现的,可是你邦定一个名字却是这样的:NameComponent hostNode= new NameComponent("my host name", "host"+branchNo);  NameComponent hostDir[]={hostNode};
bankContext.rebind_context(hostDir, bankContext);你先生成一个namecomponent的实体,在生成一个她的数组然后用NamingContext的借口方法rebind_context得方法,rebind可以反复绑定。不过我到现在也不知道怎样制作树状的namingContext。另一个有意思的小实验是这样的,你run若干个server,然后你从client端去调用interface,你甚至根本就不知道有多少server,在哪里,这比较naive地给你一个给你一个启迪怎样去实现老张的load balancing。

昨天忘记说客户端怎样解析namingcontext:BindingListHolder bl=new BindingListHolder();
BindingIteratorHolder bh=new BindingIteratorHolder();  ncRef.list(1000, bl, bh);  Binding bindings[]=bl.value;你最简单地办法就是搜索这个database,for (int i=0; i<bindings.length; i++)
{  //org.omg.CORBA.Object obj = ncRef.resolve(bindings[i].binding_name);   //String objStr = orb.object_to_string(obj);    if (bindings[i].binding_type==BindingType.ncontext)
{     NameComponent nc[]=bindings[i].binding_name;  for (int j=0; j<nc.length; j++)
{ System.out.println("kind="+nc[j].kind+ " id= "+ nc[j].id); }}简而言之,namingcontext给你的事一个数组的数组,每个数组是一个namecomponet的数组,每一个namecomponent是一个map或者说对子。

二月十三日  下午睡得好舒服,可是却只睡着了一小会儿

如果有人自称学过计算机,那么问他一两个组合算法的问题;如果有人号称是大牛,那么让他去解决一些组合算法的问题;如果没有组合算法世界上根本不会有计算机科学,我觉得我在这方面非常的吃力,并不是照着算法写程序,那是一般的猴子都可以训练的出来的,我不是在贬低谁,说到底不过是条件反射,用香蕉训练猴子做算术的方法也适合于培养程序元,但是组合算法确实不可能靠这种低级的条件反射能够培养的起来的。我觉得我也许经过无限长的时间的进化最多就只能进化到猿人一级,要真的变成人可能性是不大的。

Did I re-discovered a well-known vector space?

看百年世界大战,了解了以色列的建国历史,我觉得任何一个稍有同情心的人都会支持以色列的。

二月十四日  天不冷只是灰蒙蒙的

在生活中如果某个话题变得索然无味,你不妨顾左右而言他,在email里我只好选择沉默。

二月十六日  今天有暴风雪

每天坚持去图书馆学习的誓言只执行了一天就无疾而终了,不过坚持每天去健身房倒是完成了80%,看来我的身体要比我的头脑来的听话。今天总算把midterm应付过去了,还是惊出了一身冷汗,组合算法的题目猛一看就懵了,还好是开卷考试并且是可以在家里完成的,于是我就变小程序来解答,因为我现在笨得连数数都不会了,幸好我有先见之明没有去教室里答题,不然就完蛋了。下午去教授那里才明白我自己想的那个revolving-door算法的变形只能适用于集合size为奇数的,不过我想应该是可以解决的,不过我实在是有一点点没有兴趣,因为我知道在算法方面我毫无前途索性不去努力了。最近粮草有些不继,下个月看来还得去学校问问。对了前两天我下载了firefox,虽然我从来就是微软的铁杆支持者,这一次实在是没有办法,看来微软确实是有些病入膏肓了,IE臃肿庞大的以至于我不敢开超过五个窗口,并且一大堆的pop-up广告让我烦不胜烦,我一直猜想是某种hook的机制,可是我实在不知道怎样删除,没有办法微软对不起了,我想这个公司的人也越来越没有朝气了,迟早有一天会遇到危机的,或者现在就是了。

二月十七日  今天雪停了

去实验室,我为什么不能像前辈的留学生一样起早贪黑泡实验室呢?肯定是因为他们没吃饱饭,我还有一口剩饭就不努力了。

二月十八日  今天很冷很冷的

虽然我不算勤奋,但是春假的第一天又是星期六的早上还去实验室的人毕竟没有一两个,当然我是去做我为完成的作业。本来想写一个distributed transaction protocol给tutor替我检查,结果一动笔才发现不是那么回事,正像教授说的那样,你自以为抖动了,一上讲台却发现没有什么可说的,你自以为很明白可是当你准备写下你的想法立刻就暴露了你的错误,写program之所以比写伪代码或者protocol,algorithms之类来得慢的一个原因就在于你的思想是有很多的遗漏与错误,为了帮助我思考不妨把我的想法写下来吧:每一个participant都是决策者与被决策者,也就是说他们要独立判断一个incoming的transaction的request是否和当前的冲突,所谓冲突,意味着source或者destination帐号有重叠,outgoing的destination冲突交给对方处理?(还是应该本机处理吧?)。。。刚开了个头就头疼,脖子疼,试验室里呆了一天还真得挺累的了,不写了。

二月十九日  今天还是很冷很冷的

一大清早去实验室,结果一个早上一直在为filelock交学费,最后才明白最好把filelock当作advisory也就是cooperative instead of manadatory因为这个本来是取决于操作系统,即便是号称平台无关的jvm也不能掩盖所有的问题,下午一觉醒来才证实了自己的一个可怕的怀疑,我真是笨到家了,居然该代码的时候不小心翻下这种低级错误:filePointer.seek(offset,size,toShare); if (filePointer.readFloat()!=UnDefinedData){filePointer.writeFloat(0);}...看到这个问题了吗?我本来已开始的时候小心防范现在还是着了道了。(不明白吗?想想流的特性,就是stream)。一个早上在semaphore加filelock的双重机制间写代码仿佛在惊涛骇浪上耍杂技一般的容易翻船,因为我还要时候是考虑是否exception之后系统仍然robust。

在试验室里呆了快一天,写了一个无比繁杂的近似单线程的服务器组,说是单线程但是因为JVM会对每一个请求都创建一个server instance实际上还是多线程,因此使用了大量的filelock和semaphore,交叉在一起非常的tricky,同时总算弄清楚了一点,java的filelock是mandatory的,而且对于被锁定的区域的写操作不会引起任何的exception。你获取和释放filelock最好使用semaphore来保护因为在你自己写之前也要释放,有可能你已释放立刻就被别人锁定,所以里面类似要注意的问题很多,比如如果一个标有多个线程在访问,其中只有一个会把他从一个状态写为另一个状态,而从另一个状态写回来则有很多线程,那么同布置在一边就够了,你可以节省那个当读的线程的同步开销,而另一种情形在你进入wait()之类的block状态之前一定要记得释放semaphore,否则就死定了。如果你不使用wait之类的函数也就不必notify,因为semaphore应该会自己唤醒等待的队列,java一个比较诱惑很多程序员的地方就是内部的同步机制作的很全面,让很多人舍不得放手。感觉这个程序虽然还只是初步的常识就已经让我几乎把操作系统课堂上所有的同步范例都实践了一遍,从这个角度来看我其实应该要感谢Dr. Probst我那时候无知而又莽撞,对他有很多的不敬与诅咒,实在是不应该。总体上来说我在concordia上的三年学里面,只有computer architecture这门课是外聘的一个完完全全的东郭先生,其他的教授都还是让我学到了不少东西,当然取决于我当时的悟性与态度理解的程度不同,总之,我觉得concordia不见得比其他加拿大大学差多少,网络上称之为“清华”,也就是“清一色华人”也仅仅是针对研究生和某些其他专业,计算机本科没有多少中国人,第一是辛苦,第二是大多数在国内号称学过计算机的人不愿意再上一遍,实际上这些人该不该上他们自己心里清楚。反倒是我反正都是心血乍练,兴趣盎然。不过从一个线性代数的例子我觉得中国学生应该重新审视自己,当时刚入学的时候我发现我的线性代数的基础课(不是linear algebra,而是更基础的矩阵运算),没有被免修,我就去找Dr.Ford理论,他就简单地写了一个向量问我了一个简单的问题,我当时根本就不知道他再问什么,那时候根本就不知道原来线性代数不止是解行列式,立刻没有脾气去上课了,后来意外地被免修了,还恋恋不舍呢,看来东西方的教育的差别有时候比很多中国人心目中的差别要大得多,中国的历史基本上没有任何数理的内容,中国人的思维习惯也投机取巧的成分多很多。

二月二十一日  今天又下雪了

一大清早去实验室,路上明白了一个道理,java让程序员成了傻瓜,我原来写TCP的packet习惯了没有想到java竟然把一个connection包装起来了,也就是说你每次建立一个java的socket连接实际上内部使用匿名的port number使得你可以直接获得回复,我结果傻傻地自己去用类似selector之类的技术实在是多余。另一个我没有想明白的地方现在也明白了,java的filelock是在JVM之上的mandatory的,实际上很好理解,因为不管操作系统的filelock机制如何,你在JVM上的文件都是完全被监控的,这也就是为什么我用两个不同文件指针,其中一个设定了filelock另一个也被锁定了,在感觉上应该是cooperative or advisory的,在应用上看起来是mandatory的。另一个namingcontext的问题还不是很清楚,我使用的是persistent的也就是说先前的namingcontext都被保存在文件里了,我想要unbind总是不成功。目前我对于java server端的multi-thread有了一个初步的认识,我的想法是这样的,在每一个server内部程序员当作单线程来编程,但是每次有一个请求java idl或者java的CORBA会创建一个server的instance来达到multi-thread的,这样就要求你非常小心你的static与非static变量,如果你要做线程同步一定要运用这些static的global variable.同时在联合使用filelock和semaphore上我已经比较有体会了,尽量不要到处乱throw exception,这是一个如同goto或者break的坏习惯因为它会把程序的流程搞乱,最好的做法使用变量来做flag。而exception的原则是你对于不知道什么样的错误才应该使用,对于你知道的类型,你应该处理而不是简单抛出留给别人处理,当然有很多人不同意这个观点,我仅仅是这样建议,因为,exception的效率不是大问题,最主要的是原来应该改作的一些工作有可能没有作,比如semaphore,socket,filelock等等的释放,这是一个主要问题,java虽然号称垃圾回收但是绝不可能做到资源回收,也就是说非内存的管理是无能为力的,我就遇到了不少socket没有释放占用端口的问题,比如我仅仅需要得到localhostname而财大气粗第new一个socket,使用getlocalhost.gethostname之类的方法,结果很随意地把监听端口给了这个临时socket最后又close了结果下次运行这个端口就不能用了。在一个非常intuitive的低级错误就是filelock以后自己要使用也要先release,但是在多线程的环境下有可能被别人抢到这个filelock,因此我必须用一个semaphore去同步tryLock的方法,这里面就埋藏了很多的陷阱。比如从效率的角度看RPC是很慢的如果你获得semaphore之后要去call RPC或者socket,最好用filelock等到rpc或者socket返回以后再来重新获得semaphore。

二月二十二日  今天又下雪了

一大清早去实验室奋战到下午两点才发现了其中的错误,我的filelock,semaphore等等的synchronization都是无懈可击的问题出在我对于sun公司过高的期待,这些白痴让我昨天喜出望外以为socket建立的inputStream,outputStream可以区分“session”,也就是用一个匿名的回电Portnumber,实际上没有这么回事,我还是得自己实现,虽然无比的简单可就是没有人去做,回来后又累又饿,休整了一下午,一锅水的土豆被烧干了,我居然躺在床上看东西方冷战历史的纪录片里睡着了,侥幸没有造成大的灾难只不过在我n次烧糊锅的纪录里加了一次土豆而已,(n>=5/月)。现在继续出击去实验室。有奋战了一个晚上,就吃了一个土豆和同学的一条巧克力棒,不过终于解决了这个问题,其实我花了五六个小时trace仅仅因为我随手一行的错误,真是一个教训,在这种server的tracing实在是痛苦,我只好把三个server上输出的结果拚到一个文件里一条纪录一条记录的比对,实在是辛苦。不过也证实了我刚刚说的是错的,java的socket的确是实现了connection的功能,因此多个thread同时监听一个端口是可以各自得到各自的消息的,我因为怀疑这一点还自己去写了一个实现,其实很简单,就是选择一个portnumber,然后当作参数传给listener,以便他回答得时候用。当然你必须对于这个portnumber的选择进行同步。写完了我发现其实不需要,因为java确实是实现了,否则我的服务器有多个server instance的时候大家都监听同一个portnumber,你怎么能区分回答呢?把这个作业贴出来吧,实在是因为这几天太辛苦了,虽然我知道很多人很早就完成了,我还是对我自己的这个作业情有独钟,毕竟多线程的服务器程序是很不好写的,尤其要防止死锁ᦁ