2010年5月22日星期六

go language

差不多一个月前我仔细看了 Tim C, Erlang, Java and Go Web Server performance test, 并在我自己的笔记本上跟着使用 ab 做了一些测试, 其中还测试了两个 Python 的 web 框架, web.py Tornado , web.py 弱得简直不堪使用了, 而在Asynchronous Servers in Python 测试中性能强悍的 Tornado 应该算是我所知道的 Python web 框架中较好的一个了, 不过也不是很好,对比其他非 Python 的 web server ,哈哈。 go 的并发性能还是不错的,这让我很想学习各种 go 的应用。 于是我下载了几个跟 go 相关项目的源代码, 包括 web.go Go-Redisgomemcached gosqlite3。 无一例外的,都不能编译成功使用。

其中最常见的一个问题是,我的 go 环境对“;”的严格要求, 而这些新的项目是在比较新的 go 环境中开发的,很多地方已不需要添加“;”。 话说我的 go 版本比较低,是去年年底 2009,12,11 的源码编译的。 于是我开始一个个地给那些我的 go 环境需要“;”的地方添加“;”, 然而这是一件浩大的工程。。。遂放弃了。。。

心想,go 语言也真是的,这么普通的规则也更改了, 哪天真的用其做了一些东西出来,升级岂不是要整死人了?

不过真的很看好 go 语言,等我有了比较好的网络环境了再更新 go 的源代码, 领略一下这些构建在优秀的 go 语言上的新项目的魅力吧!

附:

一个简单的 Hello world 的 go server :

package main

import (
"http";
"io";
"runtime";
)

func HelloServer(c *http.Conn, req *http.Request) {
io.WriteString(c, "hello, world!\n");
}

func main() {
runtime.GOMAXPROCS(2); // 2 cores
http.Handle("/", http.HandlerFunc(HelloServer));
err := http.ListenAndServe(":8080", nil);
if err != nil {
panic("ListenAndServe: ", err.String())
}
}

一个粗糙的 fibonacci :

package main

import "fmt"

func main() {
var a uint8 = 0;
var b uint8 = 1;

for i :=0; i<10; i++ {
a, b = b, a + b;
fmt.Printf("%d\n", a);
}
}

一个简单的 channel 例子 (摘自 infoq-cn):

package main

import "fmt"

func main() {
ch := make(chan int);

go func() {
result := 0;
for i:=0; i<100000000; i++ {
result = result + i
}
ch <- result;
}();

/* Do something for a while */
fmt.Println("Have a rest!");
fmt.Println("Have a rest, too!");

sum := <- ch; // This will block if the calculation is not done yet.
fmt.Println("The sum is:", sum);

/* create a channel with buffer size 5 . */
ch2 := make(chan int, 5);
/* Send without blocking, ok will be true if value was buffered. */
ok := ch2 <- 42;
/* Read without blocking, ok will be true if a value was read. */
val, ok := <-ch2;
fmt.Println("ok is:", ok);
fmt.Println("val is:", val);
}

一篇比较全面介绍 Go 语言的文章: Go Lang介绍

--
http://magicoding.appspot.com/entry/1
2010,04,27

二分查找算法

JavaEye 在几天前发表了一篇关于二分查找算法的文章: 你是那10%可以实现二分查找算法的程序员吗?,讲得好像让所有的程序员都很尴尬的样子。最后文章还给出了一位 JavaScript 高手对二分查找算法的实现。但是这个算法其实也是有 bug 的。。。我们可以查看 Python 里的 bisect 模块,对于二分查找算法,分为 bisect_right 和 bisect_left 两种情况,这是由于所查找的元素在预排序算法中可能有多个存在或者元素可能会是一种复杂的数据结构,所以当然就必须考虑是查找左边的位置还是右边的位置,或者插入左边的位置还是右边的位置了。对于简单的元素不需要考虑插入左边的位置还是右边的位置,不过 Python 文档中举的例子中的元素是个复杂的数据结构,所以需要考虑这种需求。

附上那位写了《JavaScript高级程序设计》的作者使用 JavaScript 实现的代码:

//Copyright 2009 Nicholas C. Zakas. All rights reserved.
//MIT-Licensed, see source file
function binarySearch(items, value){

var startIndex = 0,
stopIndex = items.length - 1,
middle = Math.floor((stopIndex + startIndex)/2);

while(items[middle] != value && startIndex < stopIndex){

//adjust search area(调整查找范围)
if (value < items[middle]){
stopIndex = middle - 1;
} else if (value > items[middle]){
startIndex = middle + 1;
}

//recalculate middle(重新计算中项索引)
middle = Math.floor((stopIndex + startIndex)/2);
}

//make sure it's the right value(确保返回正确的值)
return (items[middle] != value) ? -1 : middle;
}

可以在 Firebug 或者其他浏览器的 JavaScript 调试器中测试这段代码, 也可以把这段代码翻译成 Python 代码,再添加一个小小的测试:

# coding=utf8
def binarySearch(items, value):

startIndex = 0
stopIndex = len(items)
middle = (stopIndex + startIndex) // 2

while items[middle] != value and startIndex < stopIndex:

#adjust search area(调整查找范围)
if value < items[middle]:
stopIndex = middle - 1
elif value > items[middle]:
startIndex = middle + 1

#recalculate middle(重新计算中项索引)
middle = (stopIndex + startIndex) // 2

#make sure it's the right value(确保返回正确的值)
return (items[middle] != value) and None or middle

if __name__ == '__main__':
items = [1, 2, 3, 4, 4, 4, 4, 4, 5, 6]
print binarySearch(items, 4)

检测运行一下,当然就发现问题了。

最后附上 Python 标准库中的实现代码:

## from file: /path/to/python-install-prefix/lib/pythonx.x/bisect.py
def bisect_right(a, x, lo=0, hi=None):
"""Return the index where to insert item x in list a, assuming a is sorted.

The return value i is such that all e in a[:i] have e <= x, and all e in
a[i:] have e > x. So if x already appears in the list, a.insert(x) will
insert just after the rightmost x already there.

Optional args lo (default 0) and hi (default len(a)) bound the
slice of a to be searched.
"""

if lo < 0:
raise ValueError('lo must be non-negative')
if hi is None:
hi = len(a)
while lo < hi:
mid = (lo+hi)//2
if x < a[mid]: hi = mid
else: lo = mid+1
return lo

bisect = bisect_right # backward compatibility

def bisect_left(a, x, lo=0, hi=None):
"""Return the index where to insert item x in list a, assuming a is sorted.

The return value i is such that all e in a[:i] have e < x, and all e in
a[i:] have e >= x. So if x already appears in the list, a.insert(x) will
insert just before the leftmost x already there.

Optional args lo (default 0) and hi (default len(a)) bound the
slice of a to be searched.
"""

if lo < 0:
raise ValueError('lo must be non-negative')
if hi is None:
hi = len(a)
while lo < hi:
mid = (lo+hi)//2
if a[mid] < x: lo = mid+1
else: hi = mid
return lo

嗯,学习算法知识的话,到 Python 的标准库中查看源代码也是一种非常好的学习方式啊!

--
http://magicoding.appspot.com/entry/0
2010,04,26

2010年5月6日星期四

谢谢大家的关注

谢谢大家关注我的博客。
由于去年离职之后到现在一直没有工作,所以未能翻墙来更新维护这个博客,今天使用一款叫做 Mr.zhang 的工具翻墙发了这些文字。
目前用 Tornado 写了个 blog 放在 Google AppEngine 上,不需翻墙访问。
http://magicoding.appspot.com
等我有了工作了再维护这个博客了。
Fedora 13 好像也快出来了,好期待啊!

2009年12月29日星期二

Fedora 12 中的 3D加速

Fedora 12 中的 3D加速

========================================
3D accelated in Fedora 12
LinFeiYu 2009,12,27

我的笔记本是 Gateway T6832c ,显卡为 HD2400XT ,Fedora 12 及 RPMFusion 中暂时没有 AMD 官方驱动的 rpm 包。默认情况下没有开启显卡的 3D加速功能。glxgear 帧速不到 300fps ,也开不了桌面特效。虽然是这样,但是视频播放还是挺流畅的。
不过偶然的一次我装了一个包之后就有了 3D加速功能啦,这个包就是 mesa-dri-drivers-experimental 。根据 yum info mesa-dri-drivers-experimental 得知这个包其实是一个试验性质的 DRI 驱动。不过挺好的,装完之后 glxgear 的帧速将近 2000fps 。桌面特效很流畅!

2009年11月30日星期一

Fedora 11 到 Fedora 12 升级历险

Fedora 11 到 Fedora 12 升级历险

===========================
Fedora 11 upgrade to Fedora 12 travel
LinFeiYu, 2009,11,28

按照官方的升级建议使用 preupgrade 满以为可以很快地升级成功。不过过程很是辛苦,因为 preupgrade 并不完美。

1. 下载升级安装所需要的文件

虽然我使用几个非官方的软件源,但是升级中依赖的解决却很是顺利。在下载了大量的 metadata 之类的信息文件之后,开始漫长的软件包的下载,一共需要下载大约 1.1GB 。下载时候的速度并不受到 /etc/yum.conf 的控制,这点出乎我的意料。缓慢的下载速度导致我在下载中必须暂停,然而目前 preupgrade 的第一个大问题是,在继续下载升级的过程中出现了 bug ,经常出现的问题是由于所有用于 preupgrade 的 metadata 都下载在 /var/cache/yum 中了,所以继续升级的时候它要么出现可以重启升级的“成功”消息,要么是扔出一个 preupgrade Python执行代码的错误(也就是 bug538118 https://bugzilla.redhat.com/show_bug.cgi?id=538118),这些都使得升级无法正常继续。在我完全没有看完 bug538118 页面上的所有回帖之后做了一些傻事。google 到的大部分解决方案就是把所有 preupgrade 已经下载的 metadata 信息文件和软件包统统删除::

# rm -rf /var/cache/yum/preupgrade*

这导致了我又一次次的下载所有的升级相关文件,既浪费了大量的时间也浪费了大量的带宽。而且没有充足的时间一次性地完成这个艰巨的任务。知道我看到了 Comment #26 之后才摆脱这个没完没了的升级下载过程。Comment #26 提供的方法是只删除已经下载的 metadata 信息文件::

# rm /var/cache/yum/preupgrade-*/!(packages)

相对来说所有的软件包都保存,只需要在暂停之后重新下载几十 MB 的 metadata 信息文件,已经是很好的解决方法了。

等升级下载完成之后以为接下来会很顺利,然而这却让我浪费了将近一周的时间。。。

2. 安装新的软件包

preupgrade 升级下载完成之后,按照提示信息,重启了机器,恶梦于是真正开始了。preupgrade 添加了一条 GRUB 启动条目,重启之后就进入这个启动条目了。这是经典的 Fedora 安装界面。然而,升级并没有开始,而是出现无法设置 FAT32 分区的错误,我觉得很奇怪,重启机器进入原来的 Fedora 11,将 /etc/fstab 中 FAT32 分区挂载条目注释掉。重新进入安装程序己可开始真正的安装,晕。安装软件包安装完之后,是否有重新安装设置 GRUB 我已经不太清楚了,可能我就在这个地方出了问题。然后就是提示信息说安装已经成功,可以重启机器了,在忍受了安装 1400 多个安装包之后我想终于可以舒服地松口气了。然而!重启之后,我的笔记本再也无法找到硬盘上的任何系统了。

3. 进入新的系统

这里我需要说明下我的硬盘的分区情况::

/dev/sda1 NTFS C:\
/dev/sda5 NTFS D:\
/dev/sda6 NTFS E:\
/dev/sda7 NTFS F:\
/dev/sda8 NTFS G:\
/dev/sda9 NTFS H:\
/dev/sda10 NTFS I:\
/dev/sda11 FAT32 J:\
/dev/sda12 SWAP
/dev/sda13 ext3 Fedora
/dev/sda14 ext3 Fedorahome
/dev/sda15 ext3 Archlinux
/dev/sda16 ext3 Archlinuxhome

Fedora 安装在 /dev/sda13 , Fedora 的 /home 目录挂载于 /dev/sda14
Archlinux 安装在 /dev/sda15 , Archlinux 的 /home 目录挂载于 /dev/sda16
GRUB 安装在各自的分区,如 Fedora 的 GRUB 安装在 /dev/sda13 , Archlinux 的 GRUB 安装在 /dev/sda15 中。 /dev/sda1 中安装的是 Windows XP ,使用 GRUB4DOS 来进入各自的 GRUB 。比如对于 Fedora 的 GRUB4DOS 条目是这样的::

title Fedora Inside
root (hd0,12)
chainloader +1

无法找到硬盘上的任何操作系统?我一开始想到的是可能升级 Fedora 的时候不小心把 GRUB 安装到 MBR 上,而且猜测是安装了 GRUB2 所致,因为不久前我安装的 debian testing 中升级了 GRUB 之后就出现类似的问题。于是我找来自己的 128M U盘 WinPE ,从 U盘 启动进入支持 SATA硬盘 的 DOS 环境,希望通过 fdisk /mbr 去掉 MBR 上的 "GRUB2" 。然而这个命令却把 U盘 中的 WinPE 的 GRUB 去掉了。。。 U盘也启动不了 WinPE 了!于是我找了几张旧光盘,其中一张是 Fedora 8 LiveCD ,可能由于刻录的原因(比如刻录速度过快,盘片质量差)花了好长时间听着“咔咔咔”的声音进入 LiveCD 中,所有分区看上去均正常,都可以正常挂载和读取数据。看上去应该是硬盘分区表启动信息的问题。用 Windows XP SP3 (集成SATA驱动)启动进入故障控制台没有找到任何 Windows 系统!试着使用 fixmbr 命令和fixboot命令然后重启机器,还是无法找到硬盘上的任何操作系统,不过用 Windows XP 安装光盘进入故障控制台已经可以找到 /dev/sda1 上的 Windows XP 了。然而,无论怎么折腾都没有效果。同事刻录了一张 GParted 的光盘也显示硬盘分区好像都正常。等到做完 U盘 WinPE ,用 U盘 启动的时候,居然进入了我的 GRUB4DOS 菜单了!然而所有 chainloader 条目都不能进入其 GRUB ,按 c 进入命令行模式,才发现 U盘 现在是 (hd0,0) ,而笔记本硬盘的分区为 (hd1,N)。这样,我更改了 Archlinux 的 root 为 (hd1,14) 之后顺利地进入了 Archlinux 中。 chroot 到 /dev/sda13 的 Fedora 系统中,一开始试着使用 grub-install 的 --recheck 参数,出现了错误,找不到任何需要的字符串。进入 GRUB 环境,试图进行修复之类的操作都提示找不到任何需要的字符串的错误。不过最后还是执行了::

root (hd0,12)
setup (hd0,12)

然后退出,重启机器。依然无法找到任何操作系统!这个时候我想到了一个最有可能的问题就是:启动分区标志的丢失。再次使用 U盘 进入 Archlinux 中,进入 fdisk /dev/sda 发现的确地,/dev/sda13 被设置为启动分区。将其调整为 /dev/sda1 ,写入分区表,退出,重启系统之后终于可以顺利找到并进入 Windows XP 的 ntldr 菜单了。太好了!接下来就是试着进入 GRUB4DOS 中的 Fedora 的 GRUB 了,然而失败了。我记起了 Fedora 的 GRUB 条目中 kernel 中使用的是 UUID ,或许该分区的 UUID 已经被更改了?于是进入 Archlinux 中 chroot 到 Fedora 中。
使用 findfs 找不到原来的 /dev/sda13 的 UUID 的对应设备信息。
使用 blkid 命令查找 udev 信息::

# blkid -o udev /dev/sda13

没有返回任何信息!而使用 tune2fs 却可以得到所有信息当然包括其 UUID ::

# tune2fs -l /dev/sda13

于是一个大胆的猜测在我脑海中形成:因为某些兼容的原因,分区的某些信息比如 UUID 至少保留在两个地方,一些比较旧的程序只能读取到一部分地方的这些分区信息,而比较新的程序可以读取到这些新区信息新的设置地方,因为升级的原因可能把旧地方的某些分区信息去掉了。我进入 Ubuntu 9.04 LiveCD 中,使用其 GParted 可以读取到完整的分区信息,而使用 WinPE 中的 PM 工具却把 /dev/sda13 当成了一个 FAT32 分区,尽管其分区号是 83 !另外一个猜测是这些分区信息可能使用了新的规则,使得旧的程序读取不到。于是我尝试一些命令来将这些信息写入到旧地方中,但是没有一个凑效。最后我做了一个最下下策的方法:重新格式化 /dev/sda13 ,并将其新的 UUID 更新到 /boot/grub/grub.cfg 和 /etc/fstab 中。这个方法中我将 /dev/sda13 格式化为 ext4 了, /etc/fstab 根分区挂载文件系统格式当然也改成 ext4 了。做完这些之后就可以进入到 /dev/sda13 中的 Fedora 12 了!除了 SELinux 对 dbus 的一个设置有问题和其他一些小问题之外好像其他一些都正常工作了。终于升级到并使用上 Fedora 12 啦!

4. 一些想法

虽然 presto 升级技术已经非常稳定和有效了,但是从旧版本升级到新版本却没有这种处理,这也让人还有些遗憾。但无论如何也将是一个需要实现的功能,是吧。

令我感到很遗憾的是,所有 Fedora 12 的软件包都已经被清除得一干二净,虽然我的 /etc/yum.conf 中设置了 keepcache=1 。在下载 preupgrade 生成的 GRUB 相关的文件中可以看到最后是删除了 /var/cache/preupgrade* 所有目录的,这个问题没有解决之前最好备份一下所有 f12 安装包。正确的做法我想应该是让所有的 f12 安装包都放在了新的 /var/cache/yum/* 各自的目录中。/etc/yum.conf 的设置也发生了一个变化,就是 cachedir 的定义?另外软件源的设置也不见了。

最后, preupgrade 这种升级方法虽然技术性强,但是还是不够成熟稳定。我想目前比较好的升级方法还是 fedora-zh 论坛中 bbbush 转载的一个文章的方法: http://bbs.fedora-zh.org/showthread.php?t=356 。而且只需要 LiveCD 作为升级安装媒质。

2009年10月15日星期四

自定义一个 zope3 的 Python 2.5 开发环境

自定义一个 zope3 的 Python 2.5 开发环境

----------------------------
LinFeiYu 2009,10,10

1. 创建一个自定义环境的目录::

$ sudo mkdir /opt/py25
$ sudo chown your_login_name:your_login_name /opt/py25

2. 首先需要自己编译一个 zlib 库

参照 limodou 前辈的文章 ( 编译Python 2.5.4带zlib http://www.zeuux.com/blog/content/1553/ ) ::

$ tar xzvf zlib-1.2.3.tar.gz
$ cd zlib-1.2.3
$ ./configure --prefix=/opt/py25 --shared
$ make
$ make install
$ make clean

3. 然后开始编译 Python 2.5.4

这里的 configure 是从 http://aur.archlinux.org/packages/python25 的 PKGBUILD 抄来的,呵呵 ::

$ tar xzvf Python-2.5.4.tgz
$ cd Python-2.5.4
$ ./configure --prefix=/opt/py25 --enable-shared --with-threads --enable-unicode
$ make
$ make install
$ make clean

4. 设置 Python 2.5 库

如果你的操作系统中已经存在一个二进制的 Python 2.5 的话,你可能不需要这一步了。

检查是否存在 /usr/lib/libpython2.5.so ,如果没有的话 ::

$ sudo ln -s /opt/py25/lib/libpython2.5.so.1.0 /usr/lib/libpython2.5.so

注意:这个方法可能不大好,如果你有好的方法,请告诉我。

5. 安装 setuptools

::

$ tar xzvf setuptools-0.6c9.tar.gz
$ cd setuptools-0.6c9
$ /opt/py25/bin/python setup.py install
$ /opt/py25/bin/python setup.py clean

7. 安装 zc.buildout

同上。

8. 一些可能用到的 Python 包的安装

基本思路同上。比如 PIL, ReportLab, xapian-bindings 等。

脚本语言之于开发及部署相关

脚本语言之于开发及部署相关

----------------------------
LinFeiYu 2009,10,05

脚本语言的简便和高效致使它们得到广泛的应用。在 Linux 发行版系统中使用脚本语言开发管理工具、应用程序现在已经非常流行。比如很多发行版的包管理程序都是用 Python 开发的。相信大家在 Linux 上使用 Python, Ruby 等脚本语言进行开发或者产品部署的时候,特别是 Python ,经常有一些比较烦心的版本冲突问题。一个比较好的解决方法我想就是自己重新编译一个需要的版本,比如在 /opt/py25 编译一个 Python 2.5 的版本,然后使用这个版本来进行开发和部署。这样做其实是有很多好处的。

1. 首先是这个版本是从源码编译的,虽然不能说比发行版提供的二进制包或者定制的包性能上好,但是我认为它可以更加的简洁和稳定,而且你可以自定义一些选项,做一些有用的优化!

2. 其次是与操作系统本身的版本分离,完全不受干扰。虽然像 zc.buildout, virtualenv 等优秀的虚拟环境构造程序可以非常好的完成这个工作,但是他们还是在跟系统紧密相连的那些版本关联,偶尔还是会发生一些意想不到的故障。

3. 升级和卸载方便。由于和操作系统中的版本完全分离,所以啥时候升级,升级成什么样子都随你折腾。卸载的话就更加方便了,几乎把目录一删除就可以了。操作系统中的版本升级也很少会影响我们自己编译的版本。最多是自己重新编译一次。