最近のMeCabの使い方

MeCabC/C++で書かれた形態素解析を行うライブラリなのですが、ちょっと疑問に思うところがあって、以下のようなコードを書きました。

require 'MeCab'

mecab_options = '-Owakati'

1000.times do |n|
  begin
    tagger = MeCab::Tagger.new(mecab_options)
    # do something with tagger
  rescue => e
    raise "failed at #{n + 1} times, [#{e.class}] #{e.message}"
  end
end

マシンスペックに依りますが、大体例外が発生します。MeCab::Taggerインスタンスが破棄されているにも関わらず! 僕のMacBook Air(メモリ2GB)で試したところ、"failed at 70 times, [RuntimeError] "と、大体70回MeCab::Tagger.newを呼んだところで落ちます。例外の内容は不明。

プロセスどうなってんのと見てみると、メモリを13GBほど消費してました。ひどい。多分mallocに失敗とかそんなところでしょうか?

どうやらMeCab 0.99からマルチスレッドに対応したようで、本家のドキュメントのコード例も変わってました。要はマルチスレッドでMeCab::Taggerインスタンスをもりもり作る場合はMeCab::Modelのインスタンスを作り、そこからMeCab::Taggerインスタンスを生成しろよ、ってことみたいです。もしMeCab::Taggerインスタンスを直接生成すると、そのたびにMeCab::Modelのインスタンスが生成されるので、メモリを圧迫し、死亡、という流れのようですね。

ということでMeCab 0.99をインストールしている環境では以下のように書けば大丈夫みたいです。

require 'MeCab'

mecab_options = '-Owakati'
mecab_model = MeCab::Model.create(mecab_options)

1000.times do
  tagger = mecab_model.createTagger
  # do something with tagger
end

ちなみにMeCab::Taggerをひとつしか生成しないような環境であれば、MeCab::Taggerから直接インスタンスを生成しても構いません(コード例でもそう書いてある)。