我正在使用这个marisa trie库的自定义Cython包装器作为键值多图.
我的trie条目看起来像key 0xff data1 0xff data2
映射key
到元组(data1, data2)
.data1
是一个可变长度的字符串,但data2
始终是一个4字节的无符号整数.这0xff
是一个分隔符字节.
从理论角度来看,我知道trie不是最优化的数据结构,但是各种实际考虑因素使其成为最佳选择.
在这个用例中,我有大约1000万到2000万个密钥,每个密钥平均有10个数据点.data2
对于许多条目来说是多余的(在某些情况下,data2
给定密钥的所有数据点总是相同的),所以我想到了最频繁的data2
输入并("", base_data2)
为每个密钥添加了一个数据点.
由于MARISA trie,据我所知,没有后缀压缩,并且对于给定的密钥,每个data1
都是唯一的,我假设这将为使用冗余密钥的每个数据元组节省4个字节(加上添加一个4字节的"值") "为每把钥匙).重建了trie后,我检查了冗余数据不再存储.我预计序列化和内存大小都会大幅减少,但实际上磁盘上的trie从566MB增加到557MB(并且加载的trie的RAM使用量也有类似的减少).
由此我得出结论,没有后缀压缩我一定是错的.我现在用多余的data2
数字存储条目key 0xff data1 0xff
,所以为了测试这个理论,我删除了尾随0xff
并调整了使用trie处理的代码.新的trie从557MB下降到535MB.
因此,删除单个冗余尾随字节比删除相同数量的4字节序列提高了2 倍,因此后缀压缩理论是错误的,或者它以某种非常复杂的方式实现.
我剩下的理论是,在("", base_data2)
trie中更高点添加条目会以某种可怕的方式抛出压缩,但是当我从中删除多于下来时,它应该只增加4个字节.线索.
我对修复并不乐观,但我非常想知道为什么我会看到这种行为!感谢您的关注.
我在16GB,2.7GHz i5,OSX 10.11.5机器上运行Python 2.7.10.
我在许多不同类型的例子中多次观察到这种现象,所以下面的例子虽然有点人为,但具有代表性.这正是我今天早些时候正在努力的事情,当我的好奇心终于被激起时.
>>> timeit('unicodedata.category(chr)', setup = 'import unicodedata, random; chr=unichr(random.randint(0,50000))', number=100)
3.790855407714844e-05
>>> timeit('unicodedata.category(chr)', setup = 'import unicodedata, random; chr=unichr(random.randint(0,50000))', number=1000)
0.0003371238708496094
>>> timeit('unicodedata.category(chr)', setup = 'import unicodedata, random; chr=unichr(random.randint(0,50000))', number=10000)
0.014712810516357422
>>> timeit('unicodedata.category(chr)', setup = 'import unicodedata, random; chr=unichr(random.randint(0,50000))', number=100000)
0.029777050018310547
>>> timeit('unicodedata.category(chr)', setup = 'import unicodedata, random; chr=unichr(random.randint(0,50000))', number=1000000)
0.21139287948608398
Run Code Online (Sandbox Code Playgroud)
您会注意到,从100到1000,正如预期的那样,时间增加了10倍.然而,1e3到1e4,它更像是因子50,然后是从1e4到1e5的因子2(所以从1e3到1e5的总因数为100,这是预期的).
我认为必须在实际的过程中进行某种基于缓存的优化,无论是在实际的过程中还是在timeit
本身,但我不能完全根据经验弄清楚是否是这种情况.进口似乎并不重要,可以通过一个最基本的例子来观察:
>>> timeit('1==1', number=10000)
0.0005490779876708984
>>> timeit('1==1', number=100000)
0.01579904556274414
>>> timeit('1==1', number=1000000)
0.04653501510620117
Run Code Online (Sandbox Code Playgroud)
从1e4到1e6,存在1e2时差的真实因子,但中间步长为~30和~3.
我可以做更多临时数据收集,但此时我还没有考虑过假设.
关于为什么非线性标度在某些中间运行次数的任何概念?
用例和背景:
我想SELECT GET_LOCK
针对固定副本使用,因此我的所有服务器都可以看到针对我的数据子集的相同锁,但将针对 mysql 的负载分配给多个副本,以便我的服务器可以在数据的不同子集上工作数据。因此我有mysql_connector_locks
和mysql_connector_data
。
其中每个connector
对象都是 sqlalchemy 引擎和 sessionmaker 的包装器。他们每个人都有
def get_mysql_session(self, isolation_level=None):
if not self.session_maker:
self.session_maker = sessionmaker()
self.session_maker.configure(bind=self.engine)
session = self.session_maker()
if isolation_level is not None:
session.connection(execution_options={'isolation_level': isolation_level.value})
try:
yield session
session.commit()
except Exception:
session.rollback()
raise
finally:
session.close()
Run Code Online (Sandbox Code Playgroud)
现在,我有了我的代码
for data_subset_id in partitioned_data:
with mysql_connector_locks.get_mysql_session() as session_locks:
try:
with get_lock(session_locks, data_subset_id):
with mysql_connector_data.get_mysql_session(
isolation_level=IsolationLevel.READ_UNCOMMITTED
) as session_data:
data = get_data(session_data, data_subset_id)
process_data(data)
except LockNotAcquired:
continue
Run Code Online (Sandbox Code Playgroud)
其中get_lock
遵循获取锁的标准方法。
出了什么问题:
每个服务器都会经历一次循环迭代,获取第二次迭代的锁,并在调用 …
NLTK版本3.4.5。Python 3.7.4。OSX版本10.14.5。
从2.7升级代码库,刚开始遇到此问题。我已经在全新的virtualenv中完成了所有软件包和扩展的全新无缓存重新安装。关于这怎么可能只发生在我身上,我很迷惑,我找不到其他在线遇到相同错误的人。
(venv3) gmoss$ python
Python 3.7.4 (default, Sep 7 2019, 18:27:02)
[Clang 10.0.1 (clang-1001.0.46.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import nltk
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/gmoss/Documents/constructor/autocomplete/venv3/lib/python3.7/site-packages/nltk/__init__.py", line 150, in <module>
from nltk.translate import *
File "/Users/gmoss/Documents/constructor/autocomplete/venv3/lib/python3.7/site-packages/nltk/translate/__init__.py", line 23, in <module>
from nltk.translate.meteor_score import meteor_score as meteor
File "/Users/gmoss/Documents/constructor/autocomplete/venv3/lib/python3.7/site-packages/nltk/translate/meteor_score.py", line 10, in <module>
from nltk.stem.porter import PorterStemmer
File "/Users/gmoss/Documents/constructor/autocomplete/venv3/lib/python3.7/site-packages/nltk/stem/__init__.py", line 29, in <module>
from …
Run Code Online (Sandbox Code Playgroud) 我使用的是python 2.7.14.可以在OSX和Linux上重现.
我有一些python类:
import cPickle
class TestClass:
def __init__(self, path_to_data=None):
self.loaded_data = None
if path_to_data:
self.load(path_to_data)
def load(self, path_to_data):
self.loaded_data = None
with open(path_to_data, 'r') as f:
self.loaded_data = cPickle.load(f)
Run Code Online (Sandbox Code Playgroud)
你可以制作一个体面的腌制词典:
>>> import cPickle
>>> d = {x:x+1 for x in range(1000000)}
>>> with open('testdict.pkl', 'w+') as f:
>>> cPickle.dump(d, f)
Run Code Online (Sandbox Code Playgroud)
并重复这样的问题:
>>> from test_py import TestClass
>>> import psutil
>>> import os
>>> process = psutil.Process(os.getpid())
>>> process.memory_info()
pmem(rss=8085504L, vms=4405288960L, pfaults=2154, pageins=0)
>>>
>>> t = TestClass('testdict.pkl')
>>> process.memory_info() …
Run Code Online (Sandbox Code Playgroud) 我有一些代码要移植到 Cython,其中有一行类似
my_list.sort(key=lambda x: x.attr[item])
Run Code Online (Sandbox Code Playgroud)
有没有一种很好的Pythonic方法来避免使用itemgetter和attrgetter的某种组合来关闭?
在Lisp Koans中,此处使用以下形式来转置矩阵:
(defun transpose (L) (apply #'mapcar (cons #'list L)))
当我解析此函数时,(cons #'list L)
返回一个列表'(#'list L1 L2 L3 ...)
,L_i
矩阵的列在哪里L
。然后apply
展开该列表,现在mapcar list
将as的列作为其参数L
,从而构造的行L
。
我想知道是否有任何原因,除了强迫一个新的Lisp学生记住并理解的用法的教学论之外cons
,还不只是写
(defun transpose (L) (apply #'mapcar #'list L))
因为L
已经是一个列表(以列(作为列表)),所以在拆包之前,这些列表apply
将#'list
位于列表中L
。
可以再简化一下吗?我认为apply
,为了将参数解包以便用于mapcar
从行中创建列表是必须的,但是我对函数式编程是陌生的。
谢谢!
python ×5
c++ ×1
closures ×1
common-lisp ×1
cython ×1
memory-leaks ×1
mysql ×1
nltk ×1
optimization ×1
performance ×1
python-2.7 ×1
python-3.x ×1
sqlalchemy ×1
timeit ×1
trie ×1