比如说, 我这里有个
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, 支持查表就行.....
1
liprais 2022-07-25 15:18:46 +08:00
自己写个 c lib
不过为啥你要在 python 里面干这种事 |
2
filwaline 2022-07-25 15:22:02 +08:00 1
这什么莫名其妙的要求? Python 这种高级语言压根不关心内存分配,你为什么要这么做?
|
3
LeegoYih 2022-07-25 15:23:55 +08:00 8
晒干了沉默
|
8
FYFX 2022-07-25 15:38:00 +08:00
为什么非得用 python 做,你找个 redis 之类的 KV 存储的塞进去不行吗
|
9
qwq11 2022-07-25 15:41:06 +08:00 via Android
cpy 自己写一个吧,直接 struct 胡上去代码量应该不超过百行
|
11
ipwx 2022-07-25 15:51:10 +08:00
|
12
wcsjtu OP |
13
ysc3839 2022-07-25 15:58:37 +08:00
如果是多个程序共用一个 dict 的话,还是建议用 redis 等独立的服务。自己写的话费时费力还可能有 bug 。
|
14
wcsjtu OP @ipwx 嗯, 这种半内存方案, 我们也尝试过, 但是对性能影响比较大。 目前还是希望有一个不需要序列化的方案,貌似就只能用共享内存了
|
16
lysS 2022-07-25 16:08:43 +08:00
为什么认为连续内存时,占用就会小?
|
17
zyx199199 2022-07-25 16:10:25 +08:00 1
需要的是类似 https://github.com/luizalabs/shared-memory-dict 这种?
或者是 multiprocessing 库里的 Manager ?类似这种 https://stackoverflow.com/questions/6832554/multiprocessing-how-do-i-share-a-dict-among-multiple-processes 以上两个都是谷歌搜索 python shared memory dict 找到的。楼主可以试试 |
18
ipwx 2022-07-25 16:14:51 +08:00
@wcsjtu 不能理解你的需求。。。。感觉 pandas.DataFrame 基本可以处理大部分情况了,你的数据内存放不下么。。
|
19
ipwx 2022-07-25 16:16:56 +08:00 2
@wcsjtu 另外如果你是 Linux 或 mac ,如果你的大表在创建以后就不修改了,那你可以用 os.fork ,直接共享 fork 前建立完成的全局变量。mac python 默认禁用了 fork 得设个环境变量。
---- 这种操作的原理基于一个事实:Linux / mac 的内核进程拷贝是按 4K page 进行 copy-on-write 的。 |
20
wzaqqq 2022-07-25 16:19:50 +08:00
/dev/shm 不知道能不能搞
|
21
daxin945 2022-07-25 16:20:52 +08:00
lmdb ?
|
22
liuxingdeyu 2022-07-25 16:22:24 +08:00
为啥要连续内存的 dict
|
24
wcsjtu OP @ipwx 确实是是内存放不下, 单个表大概占 3G 的内存。 这个表确实是只读的。我之前用的就是 fork , 但是 fork 不管用, 对于 Python 来说,由于每次 read 都会改引用计数,所以是 copy-on-read .....
|
26
ipwx 2022-07-25 16:45:33 +08:00
|
27
wcsjtu OP |
28
TimePPT 2022-07-25 17:18:09 +08:00
你这是基于啥需求啊……
|
30
786375312123 2022-07-25 17:40:56 +08:00
|
31
786375312123 2022-07-25 17:41:46 +08:00 2
@wcsjtu 为了节约内存你用 python ?你是不是队 python 有什么误解?
|
32
maggch97 2022-07-25 17:41:56 +08:00 via Android 9
我发现很多奇葩需求,原因都是开发人员只懂 a ,导致有了问题 b ,最终想用一个非常奇葩的 c 方法来解决。
|
33
maggch97 2022-07-25 17:48:12 +08:00 via Android 1
你都用 dict 了,逻辑必然不复杂,全都用 c++写这段逻辑不行吗,最终把封装好的查询接口暴露出去。
看到你上面在纠结序列化速度的问题,除非你暴露给用户的接口就是裸的 dict 查询,否则返回结果的那点序列化时间根本无足轻重。如果是暴露 dict 接口,那查询时间本来就无所谓了,你反正都要走网络或者 rpc 等等协议 |
34
listenerri 2022-07-25 17:53:32 +08:00
要不试试 zeromq 和它所支持的 ipc 进程间通讯,这样 dict 不用暴露给其他进程,本机跨进程通讯所传输的数据几乎只有一个字符串 key ,想来效率还是可以的
|
35
VYSE 2022-07-25 17:59:01 +08:00
|
36
DonDonc 2022-07-25 18:00:31 +08:00
@maggch97 So called [XY Problem]( https://en.wikipedia.org/wiki/XY_problem)
|
37
listenerri 2022-07-25 18:06:04 +08:00
@VYSE #35 楼主期望避免序列化
|
38
Muniesa 2022-07-25 18:07:57 +08:00 via Android 1
numpy 的 Structured arrays ?
|
39
xuelu520 2022-07-25 18:16:07 +08:00
那有没有一种可能,现在内存这么便宜,直接加内存呢?
|
40
sivacohan 2022-07-25 18:19:59 +08:00
sqlite memory 表?
|
41
ipwx 2022-07-25 18:24:05 +08:00 1
楼主能不能给个痛快,把最初的需求说一下。
|
42
SenLief 2022-07-25 18:32:33 +08:00 via iPhone
不可能不序列化吧?内存它又不认识 dict ,那你写入内存的时候不需要利用 struct 或者 pickle 把数据转为字节再写到内存吗?
|
43
SenLief 2022-07-25 18:34:59 +08:00 via iPhone
python 3.8 提供了 shared memory 来操作共享内存,我觉得可以通过 struct 或者 cpickle 转为字节后写入内存,效率应该是利用 python 最高的吧。
|
44
lambdaq 2022-07-25 18:42:33 +08:00 1
1. 感觉你想要的是 named tuple
2. 研究下 __slots__ 3. 遇事不决 pandas |
45
wcsjtu OP @ipwx
@786375312123 @maggch97 我这边是个 NLP 的服务, 只能用 Python 跑…… 而且有个很大的词表, 需要加载到各个进程里。 想在就是想办法节约内存, 同时还得保证性能 |
47
wcsjtu OP @SenLief 目前是想能不序列化就不序列化。 其实是可以在共享内存里存裸数据的,read 的时候加上 Python header 就行了。不过这个方法说起来简单, 但是做起来很麻烦
|
49
786375312123 2022-07-25 19:16:26 +08:00
@wcsjtu 多花点钱找个 c++开发吧。python 只是做验证的
|
50
wangyzj 2022-07-25 19:32:55 +08:00
既然追求快
为啥要 py ? |
51
wcsjtu OP |
53
786375312123 2022-07-25 19:57:46 +08:00
@wcsjtu 不存在历史原因,对于内存有限制的情况下,使用 python ,做的还是 nlp 这种事情,闻所未闻。你们公司技术的头可能对计算机基础有什么误解。
|
54
gengchun 2022-07-25 20:05:57 +08:00 1
要求性能比 Redis 高估计没有其它办法了。
共享内存思路应该是没有错的,基于 shared memory 的 dict-like 实现其实有不少,不过都处于早期阶段。自己实现一下也没有太大关系。差不多都是自己实现的。 |
55
lysS 2022-07-25 20:37:18 +08:00
共享内存考虑了并发安全了吗。。。。
|
57
wcsjtu OP @gengchun 嗯, 性能是一方面, 其实我们业务里还有很多这种词表, 有的结构比较复杂, 所以存 redis 不太合适。
|
59
whenov 2022-07-25 21:25:28 +08:00 1
pybind11 了解一下,在 C++里新建一个 Dictionary 类,给 Python 留个读取接口就行了
|
60
ipwx 2022-07-25 21:41:58 +08:00 1
|
61
air8712 2022-07-25 23:40:38 +08:00
一台机器,大 dict ,想节省内存。起一个进程加载 dict ,提供查询服务,其他进程找这个进程要数据即可。至于怎么要,就是跨进程通信的问题了。
|
62
sdshiyan2005 2022-07-25 23:52:58 +08:00 1
不知道 Arrow 项目里是不是有一部分能满足你需求: https://arrow.apache.org/use_cases/
|
63
jeeyong 2022-07-25 23:55:36 +08:00 via iPhone
盲猜一种做法
数组里包含字典,不知道是否可行。 或者有人能告知如何确定一个字典是否存储在一段连续的内存地址中? 通过获取字典元素的内存地址可行吗? |
64
zhoujinjing09 2022-07-26 01:38:18 +08:00
只读的吗?需要同时读写吗?
|
65
zhoujinjing09 2022-07-26 01:48:26 +08:00 2
根据我的经验,做到最后相比 socket 跨进程通讯性能优势很有限,你就 C++写个裸的 kv+socket 的通讯服务试试,单机通讯有 fast path ,代价应该是仅仅略高于 memcpy 。建议先说一下 QPS 的要求,共享内存是个很烦的事情,如果跨进程通讯稿代价不是瓶颈的话,性能提升很有限。
|
67
neoblackcap 2022-07-26 03:54:01 +08:00
Python 又不能有效多线程利用内存,你这个如果是跨进程访问,内存跟性能省不了多少。
如果是 nlp 的话,底层都是 C++/C 那些库。你自己封装就不知道好不好与其他组件兼容。 至于你的需求应该是可以随机访问的哈希表,但是要求这个哈希表的内存布局是连续的。连续是没问题,不过连续的话,那么肯定要有额外的空间记录偏移,否则没法让你快速读取。 capnproto 应该是能比较好完成你的需求,否则不用第三方库,你就需要自己定义一个哈希表,以及对应的内存表达格式。 话说回来,C/C++生成一个 Python 的对象其实也是一种性能消耗 |
68
wcsjtu OP |
69
wcsjtu OP @mayli 嗯, 这个就是我必须要求连续内存的原因了。 词表本身只读, 但是有可能词表中的元素与某个对象在同一个 page 上, 如果这个对象被改了, 那么词表中的元素也会被 copy 。
|
70
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} |
71
wcsjtu OP @neoblackcap capnproto 好像是个序列化的库,dict 被序列化后怎么索引呢?
这个事情如果要自己造轮子吧, 肯定要自己设计 str/int/float/list/dict 这些数据结构的, 然后还要定义他们转成 PyObject*的规则,很麻烦…… 所以我想问问大家有没有现成的轮子可以用用 |
72
ipwx 2022-07-26 11:17:38 +08:00
|
73
ipwx 2022-07-26 11:18:32 +08:00
@wcsjtu “所以我想问问大家有没有现成的轮子可以用用”
---- 看起来你不是很熟悉操作系统、编译原理、计算机组成之类的。你这一楼的需求我觉得是不可实现的,只有 C++ Microservice 还算靠谱。 |
74
ykk 2022-07-26 11:31:01 +08:00
试试 sharedmemory
|
75
laqow 2022-07-26 11:31:43 +08:00
跨进程实质都是 socket 吧,序列化逃不掉的。搞个 sqlite 把数据放硬盘不行吗,不想大量改代码就照着 dict 操作函数重新封装一下。另外如果 value 大部分都是整数或空值的话可以用稀疏矩阵算法压缩吧。
|
77
wcsjtu OP @ipwx 这个是可以做的。 就是麻烦点。 其实有点像 msgpack 这种, 只不过它没办法索引。 需要自己改造, 在 msgpack 中加上地址的元信息, 给索引用。 最好是 str/int/... 这些类型都按照 Python 的格式存储, 只是不要 PyObjectHeader 。这样读表时, 就只需要新建 header ,然后再引用表中的数据即可。 原理就是这样, 但是很麻烦,不想自己搞
|
78
echoechoin 2022-07-26 11:43:57 +08:00
直接写一个 c 语言的类 dict 库,打包成动态库,用 python 调用呗
|
79
lolizeppelin 2022-07-26 11:44:55 +08:00
那就 struct.pack 当 c 写被,定义 fmt 就好
|
80
crayygy 2022-07-26 11:49:27 +08:00
创建一个 dict 来 map key 和 index ,然后再用一个数组来存储 data 这样?
|
81
ipwx 2022-07-26 12:01:00 +08:00
|
82
changz 2022-07-26 12:25:38 +08:00 via Android
换树结构试试
|
83
dayeye2006199 2022-07-26 14:02:22 +08:00 via Android
Sqlite in memory database
|
84
neoblackcap 2022-07-26 14:49:44 +08:00 1
@wcsjtu 是序列化,但是它的序列化是特化的,反序列化的成本接近于零。但是我也没有具体试过。
然后如果你的需求还要读写的话,那么这个库就不能满足你的需求了。如果你需求还隐含跨进程访问。我还是建议你使用数据库。 |
85
mattx 2022-08-20 22:32:40 +08:00 1
https://github.com/KeyviDev/keyvi 看起来挺适合群主的需求
|