为什么在Python中关闭Sqlite3的游标

2024-03-10

使用Python时关闭游标有什么好处sqlite3模块 https://docs.python.org/2.7/library/sqlite3.html#module-sqlite3?或者它只是一个人工制品数据库API v2.0 https://www.python.org/dev/peps/pep-0249/这可能只会对其他数据库有用?

这是有道理的连接.close() https://docs.python.org/2.7/library/sqlite3.html#sqlite3.Connection.close释放资源;然而,目前尚不清楚是什么光标.close()实际上确实如此,无论它实际上释放了一些资源还是什么都不做。它的文档没有启发性:

>>> import sqlite3
>>> conn = sqlite3.connect(':memory:')
>>> c = conn.cursor()
>>> help(c.close)
Help on built-in function close:

close(...)
    Closes the cursor.

请注意,这是一个完全不同的问题为什么查询sqlite数据库时需要创建游标? https://stackoverflow.com/questions/6318126/why-do-you-need-to-create-a-cursor-when-querying-a-sqlite-database。我知道光标有什么用。问题是关于什么cursor.close()方法实际上是这样做的,以及调用它是否有任何好处。


Analysis

CPython _sqlite3.Cursor.close对应于pysqlite_cursor_close除了一些健全性检查并将其标记为已关闭之外,做这个 https://github.com/python/cpython/blob/3ad101b3/Modules/_sqlite/cursor.c#L970:

if (self->statement) {
    (void)pysqlite_statement_reset(self->statement);
    Py_CLEAR(self->statement);
}

pysqlite_statement_reset https://github.com/python/cpython/blob/3ad101b3/Modules/_sqlite/statement.c#L347依次调用sqlite3_reset https://sqlite.org/c3ref/reset.html来自 SQLite 的 C API:

调用 sqlite3_reset() 函数将准备好的语句对象重置回其初始状态,准备重新执行。任何使用 sqlite3_bind_*() API 绑定值的 SQL 语句变量都会保留其值。使用 sqlite3_clear_bindings() 重置绑定。

[...]

sqlite3_reset(S) 接口不会更改准备好的语句 S 上的任何绑定的值。

准备好的语句对象 https://sqlite.org/c3ref/stmt.htmlAPI用于绑定参数,例如在_sqlite3.Cursor.execute. So if sqlite3_clear_bindings使用时,它可能能够释放一些用于存储参数的内存,但我没有看到它在 CPython/pysqlite 中的任何地方被调用。

实验

I use 内存分析器 https://pypi.org/project/memory-profiler/绘制内存使用图表并生成逐行报告。

import logging
import sqlite3
import time

# For the function brackets to appear on the chart leave this out:
#
#     If your Python file imports the memory profiler 
#     "from memory_profiler import profile" these timestamps will not be
#     recorded. Comment out the import, leave your functions decorated, 
#     and re-run.
#
# from memory_profiler import profile


class CursorCuriosity:
  
    cursor_num = 20_000
    param_num = 200
    
    def __init__(self):
        self.conn = sqlite3.connect(':memory:')
        self.cursors = []
    
    @profile
    def create(self):
        logging.info('Creating cursors')
        sql = 'SELECT {}'.format(','.join(['?'] * self.param_num))
        for i in range(self.cursor_num):
            params = [i] * self.param_num
            cur = self.conn.execute(sql, params)
            self.cursors.append(cur)
    
    @profile
    def close(self):
        logging.info('Closing cursors')
        for cur in self.cursors:
            cur.close()

    @profile
    def delete(self):
        logging.info('Destructing cursors')
        self.cursors.clear()
    
    @profile    
    def disconnect(self):
        logging.info('Disconnecting')
        self.conn.close()
        del self.conn


@profile
def main():
    curcur = CursorCuriosity()
    
    logging.info('Sleeping before calling create()')
    time.sleep(2)
    curcur.create()
    
    logging.info('Sleeping before calling close()')
    time.sleep(2)
    curcur.close()
    
    logging.info('Sleeping before calling delete()')
    time.sleep(2)
    curcur.delete()
    
    logging.info('Sleeping before calling disconnect()')
    time.sleep(2)
    curcur.disconnect()
    
    logging.info('Sleeping before exit')
    time.sleep(2)  


if __name__ == '__main__':
    logging.basicConfig(level='INFO', format='%(asctime)s %(message)s')
    main()

我首先运行它profile导入注释掉以获得情节。

mprof run -T 0.05 cursor_overhead.py
mprof plot

然后通过导入在终端中获取输出。

mprof run -T 0.05 cursor_overhead.py
Line #    Mem usage    Increment  Occurences   Line Contents
============================================================
    51     19.1 MiB     19.1 MiB           1   @profile
    52                                         def main():
    53     19.1 MiB      0.0 MiB           1       curcur = CursorCuriosity()
    54                                             
    55     19.1 MiB      0.0 MiB           1       logging.info('Sleeping before calling create()')
    56     19.1 MiB      0.0 MiB           1       time.sleep(2)
    57   2410.3 MiB   2391.2 MiB           1       curcur.create()
    58                                             
    59   2410.3 MiB      0.0 MiB           1       logging.info('Sleeping before calling close()')
    60   2410.3 MiB      0.0 MiB           1       time.sleep(2)
    61   2410.3 MiB      0.0 MiB           1       curcur.close()
    62                                             
    63   2410.3 MiB      0.0 MiB           1       logging.info('Sleeping before calling delete()')
    64   2410.3 MiB      0.0 MiB           1       time.sleep(2)
    65   1972.2 MiB   -438.1 MiB           1       curcur.delete()
    66                                             
    67   1972.2 MiB      0.0 MiB           1       logging.info('Sleeping before calling disconnect()')
    68   1972.2 MiB      0.0 MiB           1       time.sleep(2)
    69   1872.7 MiB    -99.5 MiB           1       curcur.disconnect()
    70                                             
    71   1872.7 MiB      0.0 MiB           1       logging.info('Sleeping before exit')
    72   1872.7 MiB      0.0 MiB           1       time.sleep(2) 

以及个人方法的完整性。

Line #    Mem usage    Increment  Occurences   Line Contents
============================================================
    24     19.1 MiB     19.1 MiB           1       @profile
    25                                             def create(self):
    26     19.1 MiB      0.0 MiB           1           logging.info('Creating cursors')
    27     19.1 MiB      0.0 MiB           1           sql = 'SELECT {}'.format(','.join(['?'] * self.param_num))
    28   2410.3 MiB      0.0 MiB       20001           for i in range(self.cursor_num):
    29   2410.1 MiB      0.0 MiB       20000               params = [i] * self.param_num
    30   2410.3 MiB   2374.3 MiB       20000               cur = self.conn.execute(sql, params)
    31   2410.3 MiB     16.9 MiB       20000               self.cursors.append(cur)
Line #    Mem usage    Increment  Occurences   Line Contents
============================================================
    33   2410.3 MiB   2410.3 MiB           1       @profile
    34                                             def close(self):
    35   2410.3 MiB      0.0 MiB           1           logging.info('Closing cursors')
    36   2410.3 MiB      0.0 MiB       20001           for cur in self.cursors:
    37   2410.3 MiB      0.0 MiB       20000               cur.close()
Line #    Mem usage    Increment  Occurences   Line Contents
============================================================
    39   2410.3 MiB   2410.3 MiB           1       @profile
    40                                             def delete(self):
    41   2410.3 MiB      0.0 MiB           1           logging.info('Destructing cursors')
    42   1972.2 MiB   -438.1 MiB           1           self.cursors.clear()
Line #    Mem usage    Increment  Occurences   Line Contents
============================================================
    44   1972.2 MiB   1972.2 MiB           1       @profile    
    45                                             def disconnect(self):
    46   1972.2 MiB      0.0 MiB           1           logging.info('Disconnecting')
    47   1972.2 MiB      0.0 MiB           1           self.conn.close()
    48   1872.7 MiB    -99.5 MiB           1           del self.conn

结论

  1. 关闭一个sqlite3.Cursor不释放内存(但做了一些工作,操纵 SQLite 准备好的语句的状态)
  2. 删除/销毁游标可以释放内存
  3. 删除/销毁sqlite3.Connection释放内存(关闭则不会)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么在Python中关闭Sqlite3的游标 的相关文章

  • 高效地将大型 Pandas 数据帧写入磁盘

    我正在尝试找到使用 Python Pandas 高效地将大型数据帧 250MB 写入磁盘或从磁盘写入的最佳方法 我已经尝试了所有方法Python 数据分析 但表现却非常令人失望 这是一个更大项目的一部分 该项目探索将我们当前的分析 数据管理
  • 如何检索分配给 Django 中的组的所有权限

    我正在执行一项任务来检索分配给 Django 中的组的一组权限 我可以使用以下代码获取创建的组 但无法使用它来获取分配给它们的权限 from django contrib auth models import Group Permissio
  • 如何在seaborn热图标签中使用科学计数法?

    我正在尝试在 python 中使用seaborn 获取热图 不幸的是 即使数字非常大 它也没有使用科学记数法 我想知道是否有任何简单的方法可以转换为科学记数法或任何其他合理的格式 这是显示问题的一段代码 import seaborn as
  • 如何在动态执行的代码字符串中使用inspect.getsource?

    如果我在文件中有这段代码 import inspect def sample p1 print p1 return 1 print inspect getsource sample 当我运行脚本时 它按预期工作 在最后一行 源代码sampl
  • 如何在 numpy 数组中查找并保存重复的行?

    我有一个数组 例如 Array 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 1 1 1 2 2 2 我想要输出以下内容的东西 Repeated 1 1 1 2 2 2 保留重复行的数量也可以 例如 Repeated 1 1
  • 烧瓶 - 404 未找到

    我是烧瓶开发的新手 这是我在烧瓶中的第一个程序 但它向我显示了这个错误 在服务器上找不到请求的 URL 如果您输入了网址 请手动检查拼写并重试 这是我的代码 from flask import Flask app Flask name ap
  • 如果另一列中的值为空,则删除重复项 - Pandas

    我拥有的 df Name Vehicle Dave Car Mark Bike Steve Car Dave Steve 我想从 名称 列中删除重复项 但前提是 车辆 列中的相应值为空 我知道我可以使用 df dropduplicates
  • Karasuba算法递归过多

    我正在尝试用 c 实现 Karasuba 乘法算法 但现在我只是想让它在 python 中工作 这是我的代码 def mult x y b m if max x y lt b return x y bm pow b m x0 x bm x1
  • dask apply:AttributeError:“DataFrame”对象没有属性“name”

    我有一个参数数据框 并对每一行应用一个函数 该函数本质上是几个 sql queries 和对结果的简单计算 我正在尝试利用 Dask 的多处理 同时保持结构和界面 下面的例子有效并且确实有显着的提升 def get metrics row
  • 打印一份拥有多个家庭的人员名单,每个家庭都有多个电话号码

    我有一类 Person 它可以有多个 Home 每个 Home 都有一个或多个电话号码 我已经定义了类 但现在我正在尝试创建一个视图 其中列出每个人的所有家庭以及每个家庭地址的所有电话号码 类似于 john smith 123 fake s
  • 如何将 Pyspark Dataframe 标题设置到另一行?

    我有一个如下所示的数据框 col1 col2 col3 id name val 1 a01 X 2 a02 Y 我需要从中创建一个新的数据框 使用 row 1 作为新的列标题并忽略或删除 col1 col2 等行 新表应如下所示 id na
  • 如何让 Streamlit 每 5 秒重新加载一次?

    我必须每 5 秒重新加载 Streamlit 图表 以便在 XLSX 报告中可视化新数据 如何实现这一目标 import streamlit as st import pandas as pd import os mainDir os pa
  • Python 或 C 语言中的 Matlab / Octave bwdist()

    有谁知道 Matlab Octave bwdist 函数的 Python 替代品 此函数返回给定矩阵的每个单元格到最近的非零单元格的欧几里得距离 我看到了一个 Octave C 实现 一个纯 Matlab 实现 我想知道是否有人必须用 AN
  • 在 for 循环中访问 itertools 产品的元素

    我有一个列表列表 是附加 itertools 产品的一些其他结果的结果 我想要的是能够使用 for 循环访问列表列表中列表的每个元素 但我无法访问所有元素 我只能访问最后一个列表的元素 结果是一个非常巨大的列表列表 例如 1 2 4 3 6
  • 有没有办法拉伸整个显示图像以适应给定的分辨率?

    我最近一直在使用pygame制作游戏 遇到了一个小问题 基本上 我希望能够将屏幕上的整个图像 我已经传输到它的所有内容 拉伸到用户将窗口大小调整到的分辨率 我在 pygame 和堆栈溢出的文档中搜索了很多 但我似乎找不到答案 这可能吗 我的
  • 如何使用logging.conf文件使用RotatingFileHandler将所有内容记录到文件中?

    我正在尝试使用RotatingHandler用于 Python 中的日志记录目的 我将备份文件保留为 500 个 这意味着我猜它将创建最多 500 个文件 并且我设置的大小是 2000 字节 不确定建议的大小限制是多少 如果我运行下面的代码
  • 旧版本的 spaCy 在尝试安装模型时抛出“KeyError: 'package'”错误

    我在 Ubuntu 14 04 4 LTS x64 上使用 spaCy 1 6 0 和 python3 5 为了安装 spaCy 的英文版本 我尝试运行 这给了我错误消息 ubun ner 3 NeuroNER master src pyt
  • 如何在supervisord中设置组?

    因此 我正在设置 Supervisord 并尝试控制多个进程 并且一切正常 现在我想设置一个组 以便我可以启动 停止不同的进程集 而不是全部或全无 这是我的配置文件的片段 group tapjoy programs tapjoy game1
  • 为什么我的 PyGame 应用程序根本不运行?

    我有一个简单的 Pygame 程序 usr bin env python import pygame from pygame locals import pygame init win pygame display set mode 400
  • 在 python 中使用高精度时间戳

    嘿 我正在使用 python 处理日期时间 我想知道解析这个时间戳的最佳方法是什么 时间戳是ISO标准 这里是一个例子 2010 06 19T08 17 14 078685237Z 现在到目前为止我已经使用过 time datetime d

随机推荐