Неустранимая ошибка при использовании Python-Javabridge JVM в потоке Celery с NLTK в Mac OS X
Я использую оболочку Python для Weka, которая основана на Python-Javabridge. У меня долгое задание, и поэтому я использую для этого Celery. Проблема в том, что я получаю
A fatal error has been detected by the Java Runtime Environment:
SIGSEGV (0xb) at pc=0x00007fff91a3c16f, pid=11698, tid=3587
JRE version: (8.0_31-b13) (build )
Java VM: Java HotSpot(TM) 64-Bit Server VM (25.31-b07 mixed mode bsd-amd64 compressed oops)
Problematic frame:
C [libdispatch.dylib+0x616f] _dispatch_async_f_slow+0x18b
Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
If you would like to submit a bug report, please visit:
http://bugreport.java.com/bugreport/crash.jsp
The crash happened outside the Java Virtual Machine in native code.
See problematic frame for where to report the bug.
при запуске JVM внутри потока. Эти две строки кода используются для этого (из weka.core.jvm):
javabridge.start_vm(run_headless=True)
javabridge.attach()
Из того, что я прочитал, это, вероятно, связано с тем, что JVM не присоединена к потоку Celery. Тем не мение, javabridge.attach()
действительно бежать внутри него.
Что мне не хватает?
РЕДАКТИРОВАТЬ: Я идентифицировал код, который вызывает проблемы. Это связано с токенизатором NLTK. Следующий код (согласно ответу Вебьорна) будет воспроизводить ошибку:
# hello.py
from nltk.tokenize import RegexpTokenizer
import javabridge
from celery import Celery
app = Celery('hello', broker='amqp://guest@localhost//', backend='amqp')
started = False
@app.task
def hello():
global started
if not started:
print 'Starting the VM'
javabridge.start_vm(run_headless=True)
started = True
sentence = "This is a sentence with some numbers like 1, 2 or and some weird symbols like @, $ or ! :)"
tokenizer = RegexpTokenizer(r'\w+')
tokenized_sentence = tokenizer.tokenize(sentence.lower())
print "Tokens:", tokenized_sentence
return javabridge.run_script('java.lang.String.format("Hello, %s!", greetee);',
dict(greetee='world'))
Без запуска JVM код работает правильно. Это также работает, когда не выполняется как задача Celery. Я не понимаю, почему он падает.
РЕДАКТИРОВАТЬ 2: Это на самом деле работает в чистой среде Ubuntu ( Dockerized), но не в Mac OS X Yosemite (v10.3).
РЕДАКТИРОВАТЬ 3: Как уже упоминалось в комментариях, это работает, если from nltk.tokenize import RegexpTokenizer
делается внутри оболочки задачи, то есть внутри hello()
функция.
1 ответ
По умолчанию Celery запускает четыре отдельных рабочих процесса. (См. -c
опция командной строки для celery worker
.) Необходимо убедиться, что вы запускаете JVM во всех них. Этот пример работает для меня:
# hello.py
import os
import threading
from celery import Celery
import javabridge
app = Celery('hello', broker='amqp://guest@localhost//', backend='amqp')
started = False
@app.task
def hello():
global started
if not started:
print 'Starting the VM'
javabridge.start_vm(run_headless=True)
started = True
return javabridge.run_script('java.lang.String.format("Hello, %s!", greetee);',
dict(greetee='world'))
а также
# client.py
from hello import hello
r = hello.delay()
print r.get(timeout=1)
Установите на девственную машину Ubuntu 14.04:
$ sudo apt-get update -y $ sudo apt-get install -y openjdk-7-jdk python-pip python-numpy python-dev rabbitmq-server $ sudo pip install celery javabridge $ sudo /etc/init.d/rabbitmq-server start
Начать рабочий:
$ celery -A hello worker ... -------------- celery@a7cc1bedc40d v3.1.17 (Cipater) ---- **** ----- --- * *** * -- Linux-3.16.7-tinycore64-x86_64-with-Ubuntu-14.04-trusty -- * - **** --- - ** ---------- [config] - ** ---------- .> app: hello:0x7f5464766b50 - ** ---------- .> transport: amqp://guest:**@localhost:5672// - ** ---------- .> results: amqp - *** --- * --- .> concurrency: 4 (prefork) -- ******* ---- --- ***** ----- [queues] -------------- .> celery exchange=celery(direct) key=celery [2015-04-21 10:04:31,262: WARNING/MainProcess] celery@a7cc1bedc40d ready.
В другом окне запустите клиент пять раз:
$ python client.py Hello, world! $ python client.py Hello, world! $ python client.py Hello, world! $ python client.py Hello, world! $ python client.py Hello, world!
Заметьте в рабочем окне, что JVM запускается при первых четырех вызовах от клиента (которые идут к четырем разным процессам), но не при пятом:
[2015-04-21 10:05:53,491: WARNING/Worker-1] Starting the VM [2015-04-21 10:05:55,028: WARNING/Worker-2] Starting the VM [2015-04-21 10:05:56,411: WARNING/Worker-3] Starting the VM [2015-04-21 10:05:57,318: WARNING/Worker-4] Starting the VM