这 年头,搞网络的都得来点异步才算时髦。为啥要异步呢?你想啊,通常同步的程序,在调用函数的时候都是呆呆地等在那儿的,要是说调用的函数是CPU bound的那还好说,起码资源没啥浪费。可是网络程序大部分应该还是IO bound的吧,等IO的这茬儿你不让CPU做点其他事情,还真对不起CPU这张老脸。
Sphinx有人清楚,是一个搞全文检索的主。我们Py党很高兴的发现,它提供了Python的API。可是多看看就发现一个问题,这个api是通过访问Sphinx searchd服务来查询的,也就是说,赤裸裸的网络应用。但是深入地看看,很不幸的发现,这是一个同步程序,每次发送一个请求以后,就用 socket.recv 杵在那儿了……
咱最近不是看过twisted了么,于是便想着把这个api改成用twisted来实现。其实也是挺简单的一件事,主要就是网络部分使用twisted的事件驱动,其他的设置filter等api完全都不用改。正准备动手呢,手贱google了一把,便发现 github 上已经有这么一个玩意儿了。咱们是懒人,一看最近更新日期是4月23日,想着这也是个活跃的项目了,于是立刻抛弃了自己实现的想法,clone了一份下来。
可是郁闷的是,不管咋调整,一直得不到想要的结果,想着大约是出错了吧,print了一下错误信息:
searchd error: major command version mismatch (expected v.1.x, got v.0.138)
居然是版本协调时出错。抓了下包,确实在连接时有点问题。尽管之后的所有请求包数据都是一样的,但是服务端总是报错。仔细看了一下,原来在连接初始化时,Sphinx server会主动发送server的版本信息供客户端匹对,如果客户端发现版本ok,它也需要向服务端发送自己的版本通知server。但是这个twisted版本却没有做后面这件事。知道问题之后就好办了,操起twisted的大刀,唰唰刷地写下如下语句,便万事大吉了。
diff --git a/twisted_sphinx.py b/twisted_sphinx.py index 6d923f4..8bc1d85 100644 --- a/twisted_sphinx.py +++ b/twisted_sphinx.py @@ -178,6 +178,7 @@ class Sphinx(protocol.Protocol): self.transport.loseConnection() print 'expected searchd protocol version, got %s' % v return + self.transport.write(pack('>L', 1)) elif len(data) > 8: self._replyReceived(data)
回头再看看现在的api版本,还是不是很满意的,因为每次这个实现和原版基本是一样的,每一个Query都会直接修改当前查询属性,最理想的方式是把每次Query事物逻辑提取出来,Client只作发送接收的事。不过,懒人奥义发动,先给原作者提交了一个issue告知这个bug,其他的以后再说吧……

