【问题标题】:connection pool life cycle of py2neo.Graph: would the connections be released when the instance is no longer referenced by programmer?py2neo.Graph的连接池生命周期:当程序员不再引用实例时,连接会被释放吗?
【发布时间】:2019-12-02 12:19:34
【问题描述】:

最近我在我的代码中发现了一个可能的 http 连接泄漏问题。我在日志中收到“连接池已满,正在丢弃连接”消息,但我的代码中几乎没有并发请求。

其实我是在每次进入API函数时创建一个py2neo.Graph实例,而当它离开函数时我没有做关闭行为。

因为py2neo.Graph实例没有close()方法,官方文档中也没有关于py2neo.Graph实例生命周期的说明,所以我曾经认为实例会死掉并自动释放它的资源(比如池中的http连接)当程序员的代码不再引用它时(因为python将在一个对象的引用计数达到零时执行删除)。

那么当实例的引用被释放时,实例的实际行为是什么?管理 py2neo.Graph 实例的正确方式是什么?

【问题讨论】:

    标签: python neo4j py2neo urllib3


    【解决方案1】:

    因为 py2neo.Graph 实例没有 close() 方法,官方文档中也没有关于 py2neo.Graph 实例生命周期的说明,所以我曾经认为该实例会死掉并自动释放它的资源(比如池中的http连接)当它不再被程序员的代码引用时(因为python将在一个对象的引用计数达到零时执行删除)。

    当不再引用变量时,Python 执行删除是对的,但这不是你应该依赖的,因为不能保证它会被实际调用。

    对于网络连接,您希望显式关闭它们,通常使用上下文管理器或调用close() 方法。 urllib3 提供了执行此操作的方法,但它们必须在 py2neo 级别使用。

    所以Database对象包含一个HTTPConnector类型的Connector,如果你指定了一个HTTP URL,你可以通过connector属性访问它,然后close()它。如果您有Graph,则可以从中访问database。所以正确关闭py2neo 图表看起来像这样:

    graph = Graph(...)
    
    # use the graph...
    
    graph.database.connector.close()  # close the connection pool
    

    但我不打算这样使用py2neo:它们实际上有一个类级别的Database cache,所以当你打开多个Graph() 实例时(这就是你正在做的),那么同一个数据库将被重用,最终是同一个连接池。

    这就是为什么您可以简单地调用Database.forget_all() 类方法来清空缓存并关闭所有连接的原因。

    我不确定这是否适用于您的情况,无论如何,重用现有连接通常更快,并且 urllib3 可以很好地做到这一点,在一种情况下:您需要确保将连接释放到池中.如果您不这样做,那么您很快就会达到连接限制,这意味着创建新连接需要丢弃旧连接,这会产生您的"Connection pool is full, discarding connection" 警告。

    但老实说,这里看起来py2neo 不使用流式传输,因此所有连接都应立即放回池中,并且除非您有超过40 concurrent requests, the current default,否则您不应收到警告。如果您以minimal example 的形式分享您的实际代码,也许会更容易提供帮助。

    【讨论】:

      猜你喜欢
      • 2017-01-07
      • 2016-10-24
      • 2015-12-04
      • 1970-01-01
      • 2011-05-11
      • 2012-07-17
      相关资源
      最近更新 更多