1

以下代码导致 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 中触发 JPype在 Java 下的 neo4jneo4j.GraphDatabase中寻找。EmbeddedGraphDatabase

在交互式 Python 会话中运行此代码不会出现段错误:

>>> import webob
>>> import app
>>> debug_app = app.DebugApp()
>>> response = debug_app(webob.Request.blank('/'))
>>> response.body
'it worked'

大概是因为我在那个例子中完全避免粘贴。也许这与 Paste 使用线程妨碍 neo4j 的方式有关?我在 neo4j 论坛中注意到了一个类似的问题:http: //neo4j-community-discussions.438527.n3.nabble.com/Neo4j-CPython-Pylons-and-threading-td942435.html

...但这仅在关机时发生。

4

1 回答 1

3

问题不在于 Paste 本身,而在于使用 JPype 的 neo4j Python 绑定。Paste 创建线程来处理传入的请求;neo4j 应该是线程安全的,但是 JPype 附带了文档中的这个警告(1):

“在大多数情况下,基于 OS 级线程(即 posix 线程)的 python 线程将毫无问题地工作。唯一要记住的是在线程主体中调用 jpype.attachThreadToJVM() 以使 JVM 可以从该线程中使用。对于不是自己启动的线程,可以调用 isThreadAttachedToJVM() 进行检查。”

我找不到执行此操作的代码,但我认为 neo4j 绑定中的一些 Java 代码可能会attachThreadToJVM在导入时调用。如果是这样,当请求通过粘贴传递给工作线程,然后该线程从 neo4j 获取数据时,它正在跨越线程边界,并且可能不满足 JVM 连接规则。

import neo4j您可以通过仅在单个线程中运行来避免崩溃。在上面的例子中,这是由threading.Thread.

不幸的是,这意味着即使 neo4j 是线程安全的,但在 Python 中使用时必须将其限制为单个线程。但这并不太令人失望,考虑到。

更新:维护人员响应(2)并调查了问题,并签入了修复程序。我不知道这在 Neo4j 的哪个版本中可用,并且我再也找不到提交到他们的 github repo( 3 ),所以这代表重新测试。

于 2011-11-01T16:09:55.050 回答