2016-06-18 3 views
1

사전에서 키와 값을 추출하는 간단한 함수가 있습니다.사전에서 키와 값을 파이썬으로 추출하기 (thread-safe 방식으로)

def separate_kv_fast(adict): 
    '''Separates keys/values from a dictionary to corresponding arrays''' 
    return adict.keys(), adict.values() 

사전 "adict"가 .keys()와 .values ​​() 호출간에 수정되지 않으면 순서가 보장됩니다. 반환 진술서가 이것을 보장한다면 나는 궁금해합니다. 기본적으로 스레드로부터 안전할까요?

"adict"의 다음 구성이 멀티 스레딩 또는 필요없는 경우 더 안전합니까?

def separate_kv_fast(adict): 
    '''Separates keys/values from a dictionary to corresponding arrays''' 
    bdict = dict(adict) 
    return bdict.keys(), bdict.values() 

답변

1

내가 학습 파이썬 분해 작업 있었고, 나는이 두 통화를 보여줍니다 생각은 원자되지 않습니다

>>> 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()keys() 다음 (시리얼 values() 두 통화는 안전 necessarilly 없다. 나도 반복자되어 있지 않습니다.

당신의 단지 items()?

I을 사용하지 않는 이유가

#!/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 
,536를 너무 앞서 가서 벤치마킹, 궁금

사본은 금식 한 원자입니다 (dict()를 사용하는 것보다 약간 빠름).

+0

분해 된 버전은 분명히 통찰력을 추가합니다. 내 첫 번째 버전 generate_kv()는 .items() /. iteritems()를 사용합니다. 확실히 더 안전하지만 키퍼와 값을 약간의 속도 저하로 추출하기 위해 반복을 필요로합니다. 그리 많지는 않지만 특히 멀티 프로세싱이나 멀티 스레딩을 사용하여 사전을 생성하는 것을 고려하고 있으므로 궁금합니다. 감사! – clocker

+0

'iteritems()'나는 재진입 성 문제가 있기를 기대한다. 'items()'는 단지 키 값 쌍의 목록을 반환합니다. – rrauenza

+1

'다중 처리 (multiprocessing) '를 사용하면 객체가 프로세스에서 공유되지 않는다는 것을 깨닫게됩니까? 따라서 사전의 동시성은 문제가되지 않습니다. 내가 대답 한 [이 질문] (http://stackoverflow.com/questions/37890199/reduce-execution-time-on-huge-list-generation)에 관심이 있을지도 모른다. 그것은' 다중 처리 '. – rrauenza

관련 문제