以下代码导致Java出现段错误:
import os.path
import neo4j
from paste import httpserver, fileapp
import tempfile
from webob.dec import wsgify
from webob import Response, Request
HOST = '127.0.0.1'
PORT = 8080
class DebugApp(object):
@wsgify
def __call__(self, req):
# db = neo4j.GraphDatabase(tempfile.mkdtemp())
db = neo4j.GraphDatabase(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data'))
return Response(body='it worked')
def main():
app = DebugApp()
httpserver.serve(app, host=HOST, port=PORT)
if __name__ == '__main__':
main()
要重现,首先将该代码保存到文件中(例如,app.py),然后运行python app.py
。然后在浏览器中尝试http://localhost:8080;你应该看到Java崩溃处理程序。
Java堆栈跟踪的顶部如下所示:
Stack: [0xb42e7000,0xb4ae8000], sp=0xb4ae44f0, free space=8181k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [_jpype.so+0x26497] JPJavaEnv::NewObjectA(_jclass*, _jmethodID*, jvalue*)+0x37
C [_jpype.so+0x3c0e8] JPMethodOverload::invokeConstructor(_jclass*, std::vector<HostRef*, std::allocator<HostRef*> >&)+0x178
C [_jpype.so+0x3a417] JPMethod::invokeConstructor(std::vector<HostRef*, std::allocator<HostRef*> >&)+0x47
C [_jpype.so+0x1beba] JPClass::newInstance(std::vector<HostRef*, std::allocator<HostRef*> >&)+0x2a
C [_jpype.so+0x67b9c] PyJPClass::newClassInstance(_object*, _object*)+0xfc
C [python+0x96822] PyEval_EvalFrameEx+0x4332
C [python+0x991e7] PyEval_EvalCodeEx+0x127
我相信Python中的neo4j.GraphDatabase
触发JPype在Java下在neo4j中寻找EmbeddedGraphDatabase
。
在交互式Python会话中运行此代码不会出现段错误:
>>> import webob
>>> import app
>>> debug_app = app.DebugApp()
>>> response = debug_app(webob.Request.blank('/'))
>>> response.body
'it worked'
据推测那是因为我在这个例子中完全避免使用Paste。也许这与Paste使用线程妨碍neo4j有关?我在neo4j论坛中注意到一个类似的问题:http://neo4j-community-discussions.438527.n3.nabble.com/Neo4j-CPython-Pylons-and-threading-td942435.html
...但这只会在关机时发生。
答案 0 :(得分:3)
问题不是使用Paste本身,而是使用使用JPype的neo4j Python绑定。粘贴创建线程来处理传入的请求; neo4j应该是线程安全的,但是JPype在文档(1)中附带了这个警告:
“在大多数情况下,基于操作系统级别线程(即posix线程)的python线程将毫无问题地工作。唯一要记住的是在线程主体中调用jpype.attachThreadToJVM()以使JVM可用于对于你自己没有开始的线程,你可以调用isThreadAttachedToJVM()进行检查。“
我找不到执行此操作的代码,但我认为neo4j绑定中的某些Java代码可能会在导入时调用attachThreadToJVM
。如果是这样,当通过粘贴将请求传递给工作线程,然后该线程从neo4j获取数据时,它将越过线程边界,并且可能不满足JVM附件规则。
只需在单个线程中运行import neo4j
即可避免崩溃。在上面的情况中,这是threading.Thread
所针对的可调用对象。
不幸的是,这意味着即使neo4j是线程安全的,但是当从Python使用时,它必须被约束为单个线程。但考虑到这一点并不太令人失望。
更新:维护人员回复了(2)并调查了问题,并检查了修复程序。我不知道哪个版本的neo4j可用,并且我再也找不到它们的github repo(3)的提交,所以这代表重新测试。