使用JAVA进行串口,实在是没啥难度,而且网上已经说的够多的了,因此我也不想多废话。不过其中有个问题实在是诡异(在Linux下)。
虽然代码看上去没啥问题,但每当执行setSerialPortParams就抛出异常。
Detected: /dev/ttyM0 java.io.IOException: Not all params are supported by kernel
at com.sun.comm.LinuxSerial.nativeSetSerialPortParams(Native Method)
本以为是我 哪里搞错了,到网上一看才发现不少人遇到了和和同样的问题。问题的解决方案也是千奇百怪。有人说调用setSerialPortParams这个函数前要先sleep(10),有人说要先println。我加了print依旧失败,再往下看,有人说将setSerialPortParams这个函数放到try模块里就可以。加完try后再测试还真的好了。目前暂时只能将这个问题定义为“诡异”了。
分类目录归档:编程
Delphi的“BUG”
其实不算是Delphi的BUG了,但真的是非常非常讨厌的一个特性。
我本以为为初始化过的类就应当是nil。所以使用Assigned判断类变量是否初始化过。那知道我是否初始化过都能通过nil的检测。据说Delphi为了保证类函数的使用,会自动对这个类变量进行初始化。而当前类的指针就随便指向了一块内存空间。
感觉这个问题实在是太讨厌了,大大增加了编码出错的概率。一个变量如果并不是需要在创建的时候初始化的你就无法通过判断是否为nil检测该变量是否初始化过,除非你在创建的时候就手动赋值为nil,但这点很容易被忽略掉。
PS:
今天又和同学讨论了下这个问题。想来这个问题也是可以理解的,在C++中也存在类似的问题。看来我是被JAVA等高级语言给惯坏了。nil这个初始值虽然很简单,但确实很有用。
最近为Delphi吐血超过一公升
虽然这是一些牢骚,不过和编程还是多少有些关系的,先放这里吧。
虽不敢称对Delphi有多精通,但自信对Delphi的熟悉程度绝对超过绝大多少的Delphi的开发人员。不过最近实在是吐血,大口大口的吐,血如泉涌。粗略估计绝对吐血量绝对超过一公升。按我的说法,最近真是将数年来未遇的问题都全部给遇了个遍。这些问题搜遍地了互联网,能找到的除了问题还是问题。最的的感觉是,某些和系统结合紧密的东西还是用VC吧,毕竟都是老比家的。
那些小吐的就不说了,这里只列举些失血过度的。
最先遇到的是类似WORD的多窗口程序问题(一个程序的各个窗体都在任务栏上显示一个按钮)。其实这个问题以前也遇到过,而且网上也有不少人遇到。但这问题一只就没有过一个好的解决方案。Delphi做多窗口程序最大的问题就是,不能使用模态窗口,模态窗口很容易跑到主窗口后面,这时候就是死都出不来了,这能动用任务管理器。由于这个问题涉及到Delphi的VCL体系因此很难解决。
为了这个问题,有将互联网翻了个遍。网上应用的信息实在是太少了。我将能找到的一切方法都试了个遍,甚至连hack Delphi的方法都用过了,依旧是无疾而终。真是整到让人绝望。不过好在问题最终解决了,虽然解决方式不太优雅(应当说是,实在是太uglily了),但至少算是解决了。
然后IE插件的右键菜单问题。由于Delphi的UI并不是线程安全的,导致IE插件的右键菜单只能在当前窗口弹出,通过URL打开的新IE窗口无法弹出右键菜单。这个还好点,在网上至少还恩能找到解决方案。网上说方案有两个一个是使用API,另外一个使用线程安全的第三方控件easymenu。由于不习惯使用API(而且还不知道用API是否会带来更多的其他问题),于是先找了easymenu测试了下。死得更惨,直接挂掉。API还好,可以正常工作,不过太过繁琐。于是尝试对Delphi的控件进行扩至,可是发现根本就无法实现要求。还好,这个问题最终也算是解决了,使用的方法依旧比较无耻。
再下面的这个问题我就实在是无能为力了,血流不止。Delphi的IE插件弹出的窗口并没有使用XP的界面风格。如果是应用程序这倒好处理,放个控件就可以,但IE插件就是不行。又是放狗(google)又是划船(baidu)的,找到的都是一些鸡毛蒜皮的东西。还拉了个兄弟帮忙,结果一同被郁闷。真的让人怀疑这世界上是否真的存在这么一样东西。(后记:就在我要吐血身亡的前一秒,终于让我找到解决方案了。EmbeddedWB里面有一个XP风格支持的Demo)
就这些东西还不算,公司东西出的问题也是让人血流不止。
公司用Delphi给星空极速做了个插件,看上去好好的,也可以正常的加载。但只要程序的焦点落到这个插件里,等再移开的时候程序就挂死了。即使是最简单的ActiveForm上放一个Edit也挂。用VC写了个简单的测试程序,问题依旧。用spy++,发现按在TabControl出现消息的死循环。去掉TabControl再尝试,发现OK了。本以为将TabControl全部换成TPanel就万事大吉了。那知道测试程序好了,星空急速里还是老样子。这下更惨,以前出现消息循环的地方是在插件里,这下在星空急速里就出现消息循环了,消息根本就没有传递到插件里。死得不明不白的。再次绝望。
如果你想尝试吐血的滋味,使用Delphi写个Activex的插件吧。保证你爽到极点。
后记:
星空极速的问题终于也被我给搞定了。给我的感觉是似乎没有什么问题是解决不了的,不过吐血已经吐得够多的了,且如果有时间我似乎应当关注些其他东西了。
Django很可能存在性能问题
前言
使用Django开发WEB2.0的同学注意了,Django很可能存在性能问题,而且是灾难性的。(和算命先生一样,先吓唬吓唬人,危言耸听)
问题
WEB2.0提倡的是用户交互,因此WEB2.0站点不可能和传统站点一样,将大部分的页面都静态化。在频繁的交互中,数据库的访问必不可少。但Django的O/R
Map实在让人没底。
Django的O/R Map使用方便,但基本是个黑盒,难以进行优化。也许有人说优化是以后的事。但很多时候在最开始没有留下优化的余地,到真正需要优化的时候将苦不堪言。
对数据库的优化主要有减少数据库的访问和sql优化。将少数据库的访问可以通过cache等方式实现,这部分应当都一样,没有太多可以讨论的。对于SQL的优化,Django的O/R
Map实在封得太多,似乎也不存在太多优化余地,只能将O/R Map换成SQL。
但O/R Map在一定程度上是一种设计思想,将一个已经上线的O/R Map换成SQL并不会是一件很轻松的事。
分表也是常用的数据库优化方式,像Hibernate还可以使用Native Sql实现对分表的支持,但Django就不行。这时候有得换成Sql。
等改完后,原先优美的代码都已经变得惨不忍睹了。
相关数据
Django的应用中一直没有出现过什么大流量的网站。Django的普及程度可以说明一定问题,但或许Django本身就不适合做这个。
由于我并没有什么大流量的django站点,因此我的数据只能从网上找了。PS:我的小站,使用的是Bluehost主机中最便宜的一款,虽然没什么流量,但我进管理平台的时候几乎100%的500错误。
网站名称 使用技术 Alexa排名/收录量/PageView 服务器
Delphi盒子 ASP/SQLServer 21.05w /3.57w/3w 1G RAM
好看簿 Django 16.9w /7.05w/NA 3服务器
JavaEye ROR 2w /24.6w/15w 4G RAM
豆瓣(2006数据Quixote NA /NA /30w NA
备注:
好看簿
虽然具体流量不清楚,但参考Alexa的排名,流量应当在10w以下。
这个最早是有木头那听来的,知道是Django做的。今天在网上看到好看簿的介绍,说换了3台服务器。
对于创业期的网站来说,如果不是处于性能原有,应当不会如此奢侈。
因此猜测在单服务器时候,负载已经不太低了。
Delphi盒子
这个不属于WEB2.0页面交互比较少,因此数据库访问应当不会太过频繁。
仅仅做参考。
JavaEye
这个大家应当都比较熟悉。关于JavaEye的流量站长大人自己说得最清楚了。
HP DL145 G1,两路AMD Operton 2GHz CPU, 4G DDR RAM, 73G SCSI 15k Disk
Linux Kernel-2.6.7,lighttpd-1.4.13,MySQL-5.0,ruby-1.8.4(GC patch)
由于网站的访问量大部分集中在早上9.00到晚上9.00这12个小时的范围内。因此可以大致粗略的认为12小时处理12万动态请求,平均每小时处理1万动态请求,也就是说平均每秒处理3个动态请求。
服务器的平均CPU使用率在繁忙的时候,大概15%左右,MySQL数据库繁忙的时候平均每秒发送超过100条SQL语句,24小时平均每秒发送45条SQL语句。硬盘IO非常少
豆瓣
WEB2.0的代表,通是使用python开发。阿北在豆瓣的早期有谈论过豆瓣的性能问题。
现在cpu使用15%左右。每天30万页访问(白天每秒10次的样子),100%是动态页面。服务器的访问响应时间平均仍在0.05秒以下。
加上所有的封面照片,是有几十个G。不过这些不在数据库里。数据库现在有5G, 最多的是书的信息(40多万条)和用户收藏和评价(50多万条)。这个不包括冗余。
mysql用了innodb和myiam. 读/写频繁的用innodb, 读多写少、写多读少(比如log)或者需要full text
index的用myiam. replication/cluster还没有,不过很快会有。现在每晚用mysqldump做backup.
后记
主要是这两天看了些Scaling(可伸缩?)方面的东西。感觉Django的O/R Map的功能难以支撑Scaling。当然,对于我来说这些东西应当都不是问题,至少暂时不会是问题,还没机会遇到这些问题。
在很多时候性能问题很可能是给伪命题。对于大多数网站来说很可能根本没机会遇到性能问题。类似Django/ROR等快速开发框架的好处是可以让你快速实现你的想法,给你一个演进的机会。如果真有机会遇到性能问题,那也是一个挺不错的事情(网站发展到一定规模)。
越来越受不了JAVA的官僚主义了
前言:
发发牢骚而已。在JAVA的世界里,毕竟还是官僚主义占上风。如果在别的地方发牢骚,肯定要被人批死。在自己的blog。我的地盘我做主。
——start——
不知道是否是玩python的后遗症,还是一直以来就没有真正的喜欢过JAVA,反正最近是越来越受不了JAVA的官僚主义了。
开口一定要设计模式,不然现得你浅薄。程序中一定要用很多的框架,不然显得你很没品。千万别题JDBC,别人会当你和很无知,现在都Hibernate3.xx/EJB3了。程序中一定要有很多的接口,不然就是你的设计能力太差,连接口都不用。配置文件也是越多越好,而且都是XML的。即标准又方便,要改的时候改配置文件就可以了。
设计重要,但重要的是好的设计,不是过度设计。过度的设计同样将带来复杂度的提升。好的设计可以便于日后的扩展,但关键是很多东西是不可以预知的。一个设计不可能在最开始就做得尽善尽美。好的设计应当是一个可重构的设计。
说到设计,JAVA中的接口是滥用得最厉害的东西。在很多JAVA程序中,有事没事加一堆的接口,还美其名曰解耦。有耦合才需要解,没耦合,你解个啥。就入Dao到service间的接口,好处是实现和调用没有关系,以后换数据库方便。但,有多少情况要换数据库?即使万一真的要换,到时候再重构一次,抽取出个接口能麻烦多少。而且在经过hibernate的封装后数据库间的差别已经消灭得差不多了。
而且在大多情况下也不是加了接口就一定可以解耦的。接口只是解耦的一种途径,并不是万能药。
框架也是。现在用JAVA做WEB开发,确实很难不用框架。但框架就和设计模式一样,是为了方便开发的,如果为了框架而框架那就是自讨苦吃。在提供方便性的同时,将一些实现细节进行了封装。如果对框架的理解不够透彻,很可能带来不少问题(最近有些问题比较头大,不知道是否和hibernate+OpenSessionInView有关)。在一个工程中开发框架尽可能统一,这里说的是尽可能,不说一定(绝对就官僚了)。一些简单的问题,为什么就不可以用简单的方法处理?难道写个1+1也要MVC一吧?
配置文件也是个讨厌的东西。真不知道为什么JAVA要这么多的配置文件。哪有这么多的东西需要在发布后进行修改的。就入struts里的view,难道真的有人在项目发布后修改过?直接在代码中配置,IDE可以提供代码提示等,配置文件的书写比直接写XML流畅得多。
该死的DIV
或许真是犯贱,放着简单实用的table不用,要用div。调了半天,终于调好了。放到IE下一看,居然面目全非(firefox的调试功能比较好用,所以一般用firefox)。
看来得同时进行IE和firefox进行调试,不然等页面做好就郁闷了。
pylucene使用的问题
pylucene使用gcj进行不同平台间的移植。windows平台还好,直接使用官方的pylucene编译版本就好。可是linux平台没怎么好了。官方有提供几个常用linux的编译版本,如果没有官方的编译版本那可就得自己费点心编译了。
同样是gcj的问题。pylucene的线程必须由主线程或PyLucene.PythonThread、PyLucene.PythonThread的子线程创建,不然gcj无法对新建线程进行垃圾回收。本想在django中控制,pylucene。但django似乎为每个请求新开线程,在处理请求的时候无法创建pylucene线程。因此pylucene创建索引的过程只好单独做为一个程序跑了。
浅谈wiki的设计
虽然网上现成的wiki一大票,不过对需要进行定制开发的时候这些wiki就未必适合了。由于只是想整个最基本的wiki功能,因此打算自己整一整。 也许是有些厌倦了java,也许是想更深入的体会一下脚本语言的魅力,我决定采用django来进行开发。而且使用django有个好处,支持python的虚拟主机比支持java的好找。
虽然是重新开始整,但如果有现成的轮子当然是最好了。既然决定使用django,当然要到django的code目录去找找。diamanda,一个论坛+wiki的程序。功能很简单,但作为一个轮子还是一个不错的选择。wiki最大的特色就是版本控制,因此我对wiki的版本控制算法比较关心。看了一下版本控制部分,居然是每个版本都全部保存(我一直认为wiki应当是增量保存的)。这意味着即使是一个很小的改动也得重新保存一份。对于一篇很长的文章来说,冗余实在是大得惊人。想来也许是这个程序的问题,于是考虑去找些其他的wiki程序作为参考。除去django的项目,其他的python wiki项目也不错。反正算法什么的都可以直接用。(中途还down了个java的wiki,不过没耐心看)
又去溜达了一圈,看中了moin,python里最知名的wiki项目之一。不熟悉moin的web处理模型,看得我似懂非懂。不过基本上可以确定,他也是每个版本保存一份。
最后想想还是去看看mediawiki吧,世界上最大的wiki“基维”用的就是他。有些晕,这个也是使用全部保存的方式。想来“基维”有好几百w的数据,加上每条纪录都有多个版本,“基维”的数据库压力定是N大。不过到此我也不用去想搞啥增量算法了。众多wiki程序都是使用的全部保存模式,定是有些道理。增量算法即使有,也必定会有不少难点有待解决。
下面看看mediawikiwiki的设计吧。
mediawiki使用数据库来存储wiki数据。一张page信息表用于保存每个wiki页面的信息。可能是考虑到性能问题,真正的页面内容却没有保存在该表中,而是单独保存在text表中。表里的数据都是以blod方式保存,为什么这样做俺就不太清楚了,难道是效率更高?只有最新版本的数据才是需要索引的数据,因此单独出一张索引表,用来进行索引查询。文本内容在被索引前实现要进行一次过滤,过滤掉wiki标签等。
由于加入了版本控制,数据库中数据表中的纪录数将是实际主题的好几倍。而且随着wiki内容的丰富和完善,数据库中纪录大小将迅速膨胀。数据库的压力不言而喻。
为了减轻数据库的压力,有些wiki选用使用了更高效的办法,使用文件的形式存储wiki内容。其中moin就是这样做的。moin使用一定的规则将wiki纪录以文件的形式保存,并使用lupy(1)对文件进行索引,提供查询的支持。
为了减少每个版本都全部保存一遍所带来的巨大冗余,不少wiki都支持分段编辑。即可以对每段进行单独的编辑,在保存的时候只保存做修改那部分的内容。
(1)lupy 一个lucene的python移植版。与pylucene使用gcj移植不同的是,lupy完全使用python对lucene改写。lupy的问题是支持lucene版本比较低,只支持到1.2。
JForum开发框架介绍


JForum采用的是自己的MVC框架,因此在初次接触的时候可能会有些不习惯,但在熟悉后,该框架还是很容易使用的。在这里只是对JForum的框架进行简单的介绍以利于利用JForum进行二次开发,具体的细节请参考JForum代码。
JForum的MVC框架有些类似Struts。
先看请求的url地址/bbs/jforum.page?module=recentTopics&action=topRep_Topics_thisDay。
首先在在web.xml中配置过滤器,将所有以.page的请求交给net.jforum.JForum统一处理转发。请求在交给JForum后,JForum要获取传递过来的一些参数从而决定由哪个模块来具体处理请求。参数module,决定由哪个模块来处理。model的名字和具体class的对应关心在配置文件modulesMapping.properties里进行配置。当前操作由具体的哪个函数处理由action参数指定。action就是要执行的方法名,在无法找到指定处理方法时执行list方法。在处理完请求后,调用this.setTemplateName(TemplateKeys.SSOEXT_TOPREPMSGS_PERDAY);方法设置返回页面。其中页面和页面名称的对应关系在templatesMapping.properties中设定。
再简单的介绍一下JForum新增功能的开发流程。新建一个Action继承Command。在配置文件中modulesMapping.properties中增加新建立Action的对应关系。实现Command中定义的list方法,完成在未指定action情况下的默认操作。在templatesMapping.properties中增加返回页面的对应关系,在类TemplateKeys里增加返回页面和templatesMapping.properties配置文件里的对应关系。利用this.setTemplateName(TemplateKeys.RECENT_LIST);设置返回页面。
JForum默认采用的是FreeMarker作为表示层,但如果对FreeMarker不熟也可以采用jsp做为表示层的实现。
Delphi中的自动垃圾回收器


