rmmseg-cpp 0.2.6 & pymmseg-cpp 1.0.1

August 14, 2008 – 5:48 pm

上一篇文章中我说了 pymmseg-cpp 在 Windows 下无法正常工作的事情,经过一番折腾,现在终于能正常运行了。于是我发布了 1.0.1 版,并在 google code 申请了一个 project ,用于存放 release 包:pymmseg-cpp 在 google code 的项目主页

另外,在 github 上看到 nasi 将 rmmseg-cpp fork 了一下并对编译脚本针对 Mac OSX 进行了一点修改,便把补丁添加进来了。我身边也不好找 Mac 的机器,不过 ashchan 告诉我说打过这个补丁之后在 Mac 下挂起的问题解决掉了。于是我便顺便发布了一个 rmmseg-cpp 的新版本,没有其他改动,非 Mac 的用户不必升级。

再回过头来看看一开始 pymmseg-cpp 无法在 Windows 上工作的问题,有一个原因看起来是 C 和 C++ 之间的瓜葛,原来我写的 C 包装层大概像这个样子:

struct Token
{
    Token(const char *text, int offset, int length)
        :text(text), offset(offset), length(length) {}
    const char *text;
    int offset;
    int length;
}
 
extern "C" {
    /* ... snip... */
    Token mmseg_next_token(rmmseg::Algorithm *algor)
    {
        /* ... snip ... */
        return Token(/* ... */);
    }
}

我在用 Microsoft 的编译器编译的时候它给了一个 Warning ,大致就是说 mmseg_next_token 函数有 C linkage ,但是返回值却是一个 C++ struct 。确实,C 的 struct 是没有构造函数的,然而我觉得这样的平凡对象也没有虚函数之类的,应该 C++ 和 C 也是一样才是啊。不过我把构造函数去掉,把 Token 的定义移动到 extern "C" 段里面去再编译,发现就可以正常运行了。但是我还是有些怀疑,于是又把代码改回原来的样子,再编译了一下,发现也正常。果然问题不在这里!不过我觉得还是把这个问题记下来,C 和 C++ 之间的关系确实有些微妙,这里虽然没有出问题,但是难保会碰到雷区呢,以后写这样的代码也还是小心些为妙。 :)

那最开始的那一堆错误又从何而来呢?这是因为我一开始一直是用 MinGW 的编译器在进行测试。也许 MinGW 生成的 shared library 比较奇怪吧,我写了一个只有一个空函数的 shared library 用 ctypes 调用了一下都会报错:尝试 cdll 会说 argument 太少了;尝试 windll 会说 argument 太多了。然而应该 cdll 才是正确的类型,因为某些函数还是可以正确调用的,我随便测试了一下,发现好像在返回值是一个 struct 的时候就会出现这个问题,例如:

extern "C" {
 
    struct Token
    {
        const char *text;
        int offset;
        int length;
    };
 
    Token call_foo(Token *t)
    {
        return Token();
    }
}

不过我暂时没有打算深究这个问题了,也许 MinGW + Python ctypes 本身就是一个比较奇怪的搭配吧,再加上 ctypes 在 Windows 下检查参数个数是否传递正确的方法本身就是比较 tricky 的,和 MinGW 不兼容似乎也是可以理解的啊。 ^_^bb

  1. 18 Responses to “rmmseg-cpp 0.2.6 & pymmseg-cpp 1.0.1”

  2. pymmseg不错,下载了一个在用,我用来做提取文章关键字,改了加载字典的那块,给字典加了权重.可是感觉每次做提取都要加载字典,这个过程实在是有点耗时,能否做个把字典加载到共享内存中的,那样应该会好很多吧?我C基础比较差,改不出来了…多谢!!

    By masiqi on Aug 18, 2008

  3. @masiqi,
    你好,不用每次都加载辞典啊,程序刚启动的时候把辞典加载进来就可以了。不知道你说的是什么意思?难道是加载到 OS 的内存中,几个 mmseg 进程共享?这样大概没有 portable 的做法吧?

    By pluskid on Aug 18, 2008

  4. 我想做个类似SOHU博客那种自动提取关键字的,做个CGI,如果每次调用这个CGI都需要加载字典的话,会造成很多性能上的下降,所以,我就想,如果要是有一个进程专门把字典的HASH表加载到内存里,然后CGI直接来读,那应该会比较快一些
    当然了,如果是批量做提取的话,就没这个问题了,像你说的一样,一次加载就可以了

    By masiqi on Aug 18, 2008

  5. @masiqi,
    你好,我知道你的意思了,不过这应该是 CGI 程序的通病吧,你也可以做一个后台 server ,前台的 CGI 程序将数据发送给 server ,server 分好词之后返回结果,或者用诸如 fastcgi 之类的,解决办法应该会有不少,但是我觉得还是不应该从 pymmseg 这边来改的。 :)

    By pluskid on Aug 18, 2008

  6. 好吧,多谢,我研究一下

    By masiqi on Aug 18, 2008

  7. 说到共享内存和进程间通信的可移植做法, Boost.Interprocess 正是用来干这个事情的,已经进入 1.35 版的 Boost 。

    By rhythm on Aug 20, 2008

  8. @rhythm,
    不过 boost 真是好大啊,每次一想到自己的程序如果要依赖于这样一个东西,就有点不寒而栗…… -.-bb
    然而时间也真是过得好快,我还记得期盼 boost::asio 进入 boost 官方的遥遥无期的日子……

    By pluskid on Aug 20, 2008

  9. 哈哈,你大可用 Boost 自带的 bcp 工具把你所依赖的部分提取出来,剩下的就不用管啦

    By rhythm on Aug 21, 2008

  10. 对了, 1.36 版的 Boost 中, Asio 已经支持 Windows 下的异步文件 IO 了,总算不白起了 Asio 这个名字,可惜 UNIX 下还没有相应的解决方案。另外网络 API 方面也支持类似 select/epoll 传统方式的 Reactor 加状态机模式的编程,不一定要用 Proactor 了。

    By rhythm on Aug 21, 2008

  11. @rhythm,
    听上去不错阿,不过很久没有接触这些东西了,有机会再研究一下。

    By pluskid on Aug 21, 2008

  12. @rhythm,
    bcp ,有这种工具的?第一次听说,恩,看来以后可以放心大胆地用 boost 了,上次想用它的 hash 呢,纠结了很久还是自己实现了一个。 :-/

    By pluskid on Aug 21, 2008

  13. 貌似不错,我试试

    By masiqi on Aug 22, 2008

  14. 很赞的分词库!能否做个php5的extension呢?

    By cybergene on Sep 11, 2008

  15. @cybergene,
    唔~ php5 我不会呢,不过 mmseg-cpp 本身是相对比较独立的一个模块,懂 php 的人的话,也许很容易弄出一个库来。

    By pluskid on Sep 11, 2008

  16. @pluskid,
    嗯,也对,想想这个东西做成php的extension恐怕不合适呢。需要加载很大的一个词表,做成一个服务让php调用可能更好一点。

    By cybergene on Sep 13, 2008

  17. Hi pluskid,

    我是用MacBook Pro的,最新的rmmseg-cpp 0.2.6在我的10.5.5系统上可以正常的编译和安装,但是在运行时会抛出一个错误,大致是:

    /Library/Ruby/Gems/1.8/gems/rmmseg-cpp-0.2.6/lib/../ext/rmmseg/rmmseg.bundle: dlopen(/Library/Ruby/Gems/1.8/gems/rmmseg-cpp-0.2.6/lib/../ext/rmmseg/rmmseg.bundle, 9): Symbol not found: ___gxx_personality_v0 (LoadError)
    Referenced from: /Library/Ruby/Gems/1.8/gems/rmmseg-cpp-0.2.6/lib/../ext/rmmseg/rmmseg.bundle
    Expected in: dynamic lookup
    – /Library/Ruby/Gems/1.8/gems/rmmseg-cpp-0.2.6/lib/../ext/rmmseg/rmmseg.bundlefrom /Library/Ruby/Site/1.8/rubygems/custom_require.rb:27:in `require’
    from /Library/Ruby/Gems/1.8/gems/rmmseg-cpp-0.2.6/lib/rmmseg.rb:3
    from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:27:in `gem_original_require’
    from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:27:in `require’
    from /Library/Ruby/Gems/1.8/gems/rmmseg-cpp-0.2.6/bin/rmmseg:4
    from /usr/bin/rmmseg:19:in `load’
    from /usr/bin/rmmseg:19

    这个可能是什么问题呢?

    p.s. 再次感谢你的这个优秀的工具 :D

    By Neo on Sep 16, 2008

  18. @Neo,

    Hi, 我仔细检查了一下代码,发现有可能是因为我犯了一个低级错误。请你试一下把 ext/rmmseg/extconf.rb 里面的 CONFIG['LDShARED'] 那里的小写字母 h 改为大写的试试能否正常使用?

    By pluskid on Sep 17, 2008

  19. 啊。。。昨天邮件跟您联系的也是我。。。已经解决,非常感谢!

    By Neo on Sep 17, 2008

Post a Comment