请问大家, 有没有办法把 Python 的 dict, 存储到一段连续内存上

2022-07-25 15:08:32 +08:00
 wcsjtu

比如说, 我这里有个

table: Dict[str, List[str]] = {
	"key1": ["value1", "value2", ...],
    ...,
    "keyn": ["valuem", ...]
}

我想把这个 dict 中的所有对象(包括所有的 key, value, 以及 list), 全部存储到一段连续内存里, 同时还能支持查表操作, 比如说

values: List[str] = table_in_contigious_memory["key1"]

有没有现成的轮子可以做这种事啊。

PS: 可以不是 Python 原生的 Dict, 只要是 dict-like, 支持查表就行.....

6458 次点击
所在节点    Python
85 条回复
air8712
2022-07-25 23:40:38 +08:00
一台机器,大 dict ,想节省内存。起一个进程加载 dict ,提供查询服务,其他进程找这个进程要数据即可。至于怎么要,就是跨进程通信的问题了。
sdshiyan2005
2022-07-25 23:52:58 +08:00
不知道 Arrow 项目里是不是有一部分能满足你需求: https://arrow.apache.org/use_cases/
jeeyong
2022-07-25 23:55:36 +08:00
盲猜一种做法
数组里包含字典,不知道是否可行。
或者有人能告知如何确定一个字典是否存储在一段连续的内存地址中?
通过获取字典元素的内存地址可行吗?
zhoujinjing09
2022-07-26 01:38:18 +08:00
只读的吗?需要同时读写吗?
zhoujinjing09
2022-07-26 01:48:26 +08:00
根据我的经验,做到最后相比 socket 跨进程通讯性能优势很有限,你就 C++写个裸的 kv+socket 的通讯服务试试,单机通讯有 fast path ,代价应该是仅仅略高于 memcpy 。建议先说一下 QPS 的要求,共享内存是个很烦的事情,如果跨进程通讯稿代价不是瓶颈的话,性能提升很有限。
mayli
2022-07-26 02:31:36 +08:00
@wcsjtu 是只读的吗?如果是只读的,那就先创建这个表,然后 fork 就完事了
neoblackcap
2022-07-26 03:54:01 +08:00
Python 又不能有效多线程利用内存,你这个如果是跨进程访问,内存跟性能省不了多少。
如果是 nlp 的话,底层都是 C++/C 那些库。你自己封装就不知道好不好与其他组件兼容。
至于你的需求应该是可以随机访问的哈希表,但是要求这个哈希表的内存布局是连续的。连续是没问题,不过连续的话,那么肯定要有额外的空间记录偏移,否则没法让你快速读取。
capnproto 应该是能比较好完成你的需求,否则不用第三方库,你就需要自己定义一个哈希表,以及对应的内存表达格式。
话说回来,C/C++生成一个 Python 的对象其实也是一种性能消耗
wcsjtu
2022-07-26 10:21:18 +08:00
@ipwx
@air8712
@zhoujinjing09
嗯, 目前把 IPC 作为最后兜底方案……
wcsjtu
2022-07-26 10:23:15 +08:00
@mayli 嗯, 这个就是我必须要求连续内存的原因了。 词表本身只读, 但是有可能词表中的元素与某个对象在同一个 page 上, 如果这个对象被改了, 那么词表中的元素也会被 copy 。
cassidyhere
2022-07-26 10:38:19 +08:00
可以试试 apache arrow 的 plasma ,底层是 c++写的 In-Memory Object Store ,api 很友好:
import pyarrow.plasma as plasma
client = plasma.connect("plasma")
object_id = client.put({"a": 1})
client.get(object_id)
>>>{'a': 1}
wcsjtu
2022-07-26 10:44:40 +08:00
@neoblackcap capnproto 好像是个序列化的库,dict 被序列化后怎么索引呢?

这个事情如果要自己造轮子吧, 肯定要自己设计 str/int/float/list/dict 这些数据结构的, 然后还要定义他们转成 PyObject*的规则,很麻烦……

所以我想问问大家有没有现成的轮子可以用用
ipwx
2022-07-26 11:17:38 +08:00
@wcsjtu “ 如果这个对象被改了, 那么词表中的元素也会被 copy ”

那你这个写法稍微有点问题。从共享内存用对象应该拷出来。
ipwx
2022-07-26 11:18:32 +08:00
@wcsjtu “所以我想问问大家有没有现成的轮子可以用用”
----

看起来你不是很熟悉操作系统、编译原理、计算机组成之类的。你这一楼的需求我觉得是不可实现的,只有 C++ Microservice 还算靠谱。
ykk
2022-07-26 11:31:01 +08:00
试试 sharedmemory
laqow
2022-07-26 11:31:43 +08:00
跨进程实质都是 socket 吧,序列化逃不掉的。搞个 sqlite 把数据放硬盘不行吗,不想大量改代码就照着 dict 操作函数重新封装一下。另外如果 value 大部分都是整数或空值的话可以用稀疏矩阵算法压缩吧。
ykk
2022-07-26 11:32:28 +08:00
@ykk #74 看到了 楼主不想序列化
wcsjtu
2022-07-26 11:37:36 +08:00
@ipwx 这个是可以做的。 就是麻烦点。 其实有点像 msgpack 这种, 只不过它没办法索引。 需要自己改造, 在 msgpack 中加上地址的元信息, 给索引用。 最好是 str/int/... 这些类型都按照 Python 的格式存储, 只是不要 PyObjectHeader 。这样读表时, 就只需要新建 header ,然后再引用表中的数据即可。 原理就是这样, 但是很麻烦,不想自己搞
echoechoin
2022-07-26 11:43:57 +08:00
直接写一个 c 语言的类 dict 库,打包成动态库,用 python 调用呗
lolizeppelin
2022-07-26 11:44:55 +08:00
那就 struct.pack 当 c 写被,定义 fmt 就好
crayygy
2022-07-26 11:49:27 +08:00
创建一个 dict 来 map key 和 index ,然后再用一个数组来存储 data 这样?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/868557

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX