我有一个简单的函数,用于从字典中提取键和值。
def separate_kv_fast(adict):
'''Separates keys/values from a dictionary to corresponding arrays'''
return adict.keys(), adict.values()
我知道如果在.keys()和.values()调用之间没有修改字典“adict”,则保证顺序。我想知道的是,如果退货声明保证这一点;基本上,它是否是线程安全的?
以下“adict”构造对于多线程还是不需要更安全?
def separate_kv_fast(adict):
'''Separates keys/values from a dictionary to corresponding arrays'''
bdict = dict(adict)
return bdict.keys(), bdict.values()
答案 0 :(得分:1)
我一直在研究python反汇编,我相信这表明这两个调用不是原子的:
>>> dis.dis(separate_kv_fast)
2 0 LOAD_FAST 0 (adict)
3 LOAD_ATTR 0 (keys)
6 CALL_FUNCTION 0
9 LOAD_FAST 0 (adict)
12 LOAD_ATTR 1 (values)
15 CALL_FUNCTION 0
18 BUILD_TUPLE 2
21 RETURN_VALUE
>>>
它在多个操作码中调用键和值我相信它表明它不是原子的。
让我们看看你的bdict = dict(adict)
是如何运作的:
2 0 LOAD_GLOBAL 0 (dict)
3 LOAD_FAST 0 (adict)
6 CALL_FUNCTION 1
9 STORE_FAST 1 (bdict)
LOAD_FAST
将对adict
的引用推送到堆栈。然后我们用该参数调用dict
。我们不知道的是dict()
函数是否是原子的。
bdict = adict.copy()
给出了类似的反汇编。 adict.copy
无法拆解。
我读到的一切都说内部类型是线程安全的。所以我相信单个函数调用字典会在内部保持一致。即,items()
,copy()
,values()
,keys()
等。两个串行呼叫(values()
后跟keys()
并非必要的安全也没有迭代器。
您是否有理由不仅使用items()
?
我很好奇,所以继续进行基准测试:
#!/usr/bin/python
import timeit
import random
D = dict()
for x in xrange(0, 1000):
D[x] = str(x)
def a():
return D.keys(), D.values()
def b():
keys = []
values = []
for k, v in D.items():
keys.append(k)
values.append(v)
return keys, values
def c():
d = D.copy()
return d.keys(), d.values()
def d():
return zip(*D.items())
print timeit.timeit("a()", 'from __main__ import a')
print timeit.timeit("b()", 'from __main__ import b')
print timeit.timeit("c()", 'from __main__ import c')
print timeit.timeit("d()", 'from __main__ import d')
结果:
6.56165385246
145.151810169
19.9027020931
65.4051799774
副本是禁用的原子副本(并且可能比使用dict()稍快一些。)