4

我在想 Python 的原生 DBM 应该比东京内阁、MongoDB 等 NOSQL 数据库快得多(因为 Python DBM 的功能和选项较少;即更简单的系统)。我用一个非常简单的写/读示例进行了测试

#!/usr/bin/python
import time
t = time.time()
import anydbm
count = 0
while (count < 1000):
 db = anydbm.open("dbm2", "c")
 db["1"] = "something"
 db.close()
 db = anydbm.open("dbm", "r")
 print "dict['Name']: ", db['1'];
 print "%.3f" % (time.time()-t)
 db.close()
 count = count + 1

读/写:1.3s 读:0.3s 写:1.0s

MongoDb 的这些值至少快 5 倍。真的是 Python DBM 的性能吗?

4

2 回答 2

15

Python 没有内置的 DBM 实现。它的 DBM 功能基于广泛的 DBM 风格的第三方库,如 AnyDBM、Berkeley DBM 和 GNU DBM。

Python 的字典实现对于键值存储来说确实很快,但不是持久的。如果您需要高性能的运行时键值查找,您可能会找到更好的字典 - 您可以使用 cpickle 或 shelve 之类的东西来管理持久性。如果启动时间对您很重要(并且如果您正在修改数据,则终止) - 比运行时访问速度更重要 - 那么像 DBM 这样的东西会更好。

在您的评估中,作为主循环的一部分,您包括了 dbm 打开调用和数组查找。打开 DBM 以存储一个值并在查找之前关闭并重新打开是一个非常不切实际的用例,并且您会看到以这种方式管理持久数据存储时典型的缓慢性能(它是相当低效)。

根据您的要求,如果您需要快速查找并且不太关心启动时间,DBM 可能是一个解决方案 - 但要对其进行基准测试,只需在循环中包含写入和读取!像下面这样的东西可能是合适的:

import anydbm
from random import random
import time

# open DBM outside of the timed loops
db = anydbm.open("dbm2", "c")

max_records = 100000

# only time read and write operations
t = time.time()

# create some records
for i in range(max_records):
  db[str(i)] = 'x'

# do a some random reads
for i in range(max_records):
  x = db[str(int(random() * max_records))]

time_taken = time.time() - t
print "Took %0.3f seconds, %0.5f microseconds / record" % (time_taken, (time_taken * 1000000) / max_records)

db.close()
于 2011-10-12T11:04:28.413 回答
2

嵌入式密钥库在 python3 中足够快。以本地字典为基准,比如说

for k in random.choices(auList,k=100000000):
    a=auDict[k]
CPU times: user 1min 6s, sys: 1.07 s, total: **1min 7s**

GDBM 对此并不差

%%time
with db.open("AuDictJson.gdbm",'r') as d:
    for k in random.choices(auList,k=100000000):   
        a=d[str(k)]   
CPU times: user 2min 44s, sys: 1.31 s, total: **2min 45s**

即使是专业的预编译表,如 json 序列化列表的 keyvy,也几乎可以做到这一点。

%%time
d = keyvi.Dictionary("AuDictJson.keyvi")
for k in random.choices(auList,k=100000000):   
    a=d[str(k)].GetValue()
CPU times: user 7min 45s, sys: 1.48 s, total: 7min 47s

一般而言,嵌入式数据库,特别是当它是只读的和单用户时,应该总是期望赢得外部数据库,因为套接字和信号量访问资源的开销。另一方面,如果你的程序是一个已经有一些外部 I/O 瓶颈的服务——比如说,你正在编写一个 web 服务——,那么访问资源的开销可能并不重要。

也就是说,如果它们提供额外的服务,您可以看到使用外部数据库的一些优势。对于 Redis,请考虑集合并集。

%%time
for j in range(1000):
    k=r.sunion(('s'+str(k) for k in random.choices(auList,k=10000)))  
CPU times: user 2min 24s, sys: 758 ms, total: 2min 25s

与 gbm 相同的任务处于相同的数量级。尽管 redis 仍然慢了五倍,但它并没有慢到丢弃它

%%time 
with db.open("AuDictPSV.gdbm",'r') as d:
    for j in range(1000):
        a=set()
        for k in random.choices(auList,k=10000):
            a.update(d[str(k)].split(b'|'))
CPU times: user 33.6 s, sys: 3.5 ms, total: 33.6 s

通过在这种情况下使用 redis,您可以获得数据库的全部功能,而不仅仅是一个简单的数据存储。当然,如果有很多客户端饱和,或者有很多单次获取,与嵌入式资源相比,它的性能会很差。

至于 gdbm 竞争,Charles Leifer 在2014 年进行的一项基准测试表明,它可以在读取方面超越 KyotoCabinet,但在写入方面仍然是并列的,并且可以将 LevelDB 和 RocksDB 视为高级替代品。

于 2020-02-06T15:42:51.683 回答