5

我正在使用 gevent 在基于 Django 的 Web 系统上处理 API I/O。

我已经使用以下方法进行了猴子修补:

import gevent.monkey; gevent.monkey.patch_socket()

我已经使用以下方法修补了psychopg:

import psycogreen; psycogreen.gevent.patch_psycopg()

尽管如此,某些 Django 调用因此 Model.save() 失败并出现错误:“异步连接失败”。我是否需要做其他事情才能在 Django 环境中使 postgres greenlet 安全?还有什么我想念的吗?

4

1 回答 1

7

一篇关于这个问题的文章,不幸的是它是俄语的。让我引用最后一部分:

所有的连接都存储在django.db.connections中,它是django.db.utils.ConnectionHandler的实例。每次 ORM 即将发出查询时,它都会通过调用 connections['default']来请求数据库连接。反过来,ConnectionHandler.__getattr__检查 ConnectionHandler._connections 中是否存在 连接,如果它为空,则创建一个新连接。

使用后应关闭所有打开的连接。有一个信号 request_finished,由 django.http.HttpResponseBase.close运行。Django 在最后一刻关闭了数据库连接,当时没有人可以再使用它了——这似乎是合理的。

然而,关于 ConnectionHandler 如何存储数据库连接有一个棘手的部分。它使用threading.local,在猴子补丁后变成 gevent.local.local。声明过一次,这个结构就像它在每个绿地都是独一无二的一样工作。控制器 *some_view* 在一个 greenlet 中开始工作,现在我们在 *ConnectionHandler._connections* 中建立了一个连接。然后我们再创建几个greenlet,它们得到一个空的*ConnectionHandlers._connections*,它们从池中得到connectinos。完成新的 greenlets 后,它们的 local() 的内容消失了,数据库连接也随之消失,而没有返回到池中。在某个时刻,池变空

开发 Django+gevent 时,您应该始终牢记这一点,并通过调用django.db.close_connection关闭数据库连接。它也应该在异常时调用,您可以为此使用装饰器,例如:

class autoclose(object):
    def __init__(self, f=None):
        self.f = f

    def __call__(self, *args, **kwargs):
        with self:
            return self.f(*args, **kwargs)

    def __enter__(self):
        pass

    def __exit__(self, exc_type, exc_info, tb):
        from django.db import close_connection
        close_connection()
        return exc_type is None
于 2013-09-23T09:52:18.730 回答