2014-02-05 3 views
5

문자열 표현을 1에서 많은 수 (내 경우 20000000)로 연결하여 다른 속도 연결 방법의 속도를 테스트하고 있습니다. 결과 아무튼 나는 순진보다 빠를하는 개선 된 방법을 볼 것으로 예상하고파이썬 문자열 연결 속도

import cProfile 

count = 20000000 

def profileWrapper(f): 
    def wrapper(*args, **argv): 
     pr = cProfile.Profile() 
     pr.enable() 
     string = f(*args, **argv) 
     pr.create_stats() 
     pr.print_stats() 
     return string 
    return wrapper 

@profileWrapper 
def naiveConcat(): 
    global count 
    string = '' 
    for i in xrange(count): 
     string += `i` 
    return string 

@profileWrapper 
def improvedConcat(): 
    global count 
    string = [] 
    for i in xrange(count): 
     string.append(`i`) 
    return ''.join(string) 

@profileWrapper 
def fastestConcat(): 
    global count 
    return ''.join([`i` for i in xrange(count)]) 

print 15 * "=", "naiveConcat", 15 * "=" 
naiveConcat() 
print 15 * "=", "improvedConcat", 15 * "=" 
improvedConcat() 
print 15 * "=", "fastestConcat", 15 * "=" 
fastestConcat() 

, 그것은 '가장 빠른 방법보다 훨씬 느린 안 :하지만, 내가 테스트입니다 세 가지 방법이 있습니다 다음과 같이 보입니다 :

=============== naiveConcat =============== 
     3 function calls in 3.951 seconds 

    Ordered by: standard name 

    ncalls tottime percall cumtime percall filename:lineno(function) 
     1 0.000 0.000 0.000 0.000 cProfile.py:90(create_stats) 
     1 3.951 3.951 3.951 3.951 str_concat.py:18(naiveConcat) 
     1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 


=============== improvedConcat =============== 
     20000004 function calls in 6.990 seconds 

    Ordered by: standard name 

    ncalls tottime percall cumtime percall filename:lineno(function) 
     1 0.000 0.000 0.000 0.000 cProfile.py:90(create_stats) 
     1 5.196 5.196 6.990 6.990 str_concat.py:26(improvedConcat) 
20000000 1.322 0.000 1.322 0.000 {method 'append' of 'list' objects} 
     1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 
     1 0.473 0.473 0.473 0.473 {method 'join' of 'str' objects} 


=============== fastestConcat =============== 
     4 function calls in 3.043 seconds 

    Ordered by: standard name 

    ncalls tottime percall cumtime percall filename:lineno(function) 
     1 0.000 0.000 0.000 0.000 cProfile.py:90(create_stats) 
     1 2.539 2.539 3.043 3.043 str_concat.py:34(fastestConcat) 
     1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 
     1 0.504 0.504 0.504 0.504 {method 'join' of 'str' objects} 

개선 된 방법은 순진한 방법보다 훨씬 느립니다.

순진한 방법이 새로운 바인딩을 생성하고 각 문자열에 연결된 문자열 문자와 함께 이전 문자열을 복사하기 때문에이 방법은 의미가 없습니다.이 방법은 O (n^2) O (n) 인 다른 방법보다 느립니다.

그래서 개선 된 방법이 너무 느립니까? 내가 생각할 수있는 유일한 이유는 append 메서드이지만, this article에 따르면 append 메서드는 O (1)을 사용하므로 명확히 이유가 아닙니다. 그럼 개선 된 콘택()에서 오래 걸리는 것은 무엇입니까? 고맙습니다.

+1

신중해야합니다. "추가"를시기하지만 "결합"에 대한 결과 만 기대합니다. 기본 "% s % s"% (str1, str2) 함수를 사용하십시오. 그것은 대부분의 상황에서 가장 빠릅니다. – cox

+0

@cox, 필자는 연결 함수에서 필요하기 때문에 "추가"를 할 필요가 있습니다. 제안한 방식대로 다른 함수를 작성 했으므로 가장 느린 네 가지 중에서 가장 단순한 방법보다 느립니다. 어쩌면 몇 개의 문자열 만 연결하는 것이 더 빠를 수도 있지만 많은 양의 문자열 세그먼트를 연결하는 경우가 아닙니다. 이 경우 – elgoog

+1

의 경우 "join"이 옵션 일 수 있습니다. 파이썬/C++/... 문자열의 장점은 길이가 객체 속성에 캐시된다는 것입니다. 따라서 기본 연산의 경우 C보다 Python에서 더 나은 결과를 얻을 수 있습니다. 그러나 연결은 또 다른 짐승입니다. 와트는 데이터를 메모리에 할당하거나 채우는 것입니다. 유형은 적합하지 않습니다. 아마도 cython 함수가 더 빠를 것입니까? – cox

답변

2

개선 된Concat의 ncalls 열은 20000004 건의 함수 호출을 수행했음을 보여줍니다. 다른 알고리즘과 비교해 보면 소수에 불과합니다. 함수 호출은 파이썬에서 아주 저렴하지 않으므로 제한적으로 유지하십시오.

def foo(): 
    pass 

@profileWrapper 
def nop(): 
    for i in xrange(count): 
     foo() 
    return '' 

내가 다른 시험과 비슷한 타이밍 결과를 얻을,이 NOP (연산 없음)

에서 테스트 결과 : 나는 단지 빈 함수 정의를 호출 NOP라는 패턴, 다음과 같은 새로운 테스트를 만들어 보여주기 위해
=============== nop =============== 
20000003 function calls in 4.386 seconds 

그래서 함수 호출을하는 오버 헤드가 4.4 초 있습니다.

+0

OP에서'string + = [i]'를 사용하면 어떤 차이가 있는지 궁금합니다. – 2rs2ts

+3

@ 2rs2ts : "TypeError : 'str'및 'list'개체를 연결할 수 없습니다." map (str, array), xrange 대신 range, list comprehension 대신 generator expression을 사용했지만 fastestConcat에서는 개선하지 못했습니다. – velotron

+0

총계를 1로 줄이고, 'count = 1; time.timeit ('b = improvedConcat()', setup = 'from __main__ import improvementsConcat', number = 1)'결과가 여전히 개선 된 방법이 느리다는 것을 알 수 있습니다 :'naive : 3.40938568115e-05; 개량 : 4.10079956055e-05; 가장 빠름 : 3.09944152832e-05'.게다가, 함수 호출은 일정한 시간이 걸리므로, 순진 메소드의 연결은 연결될 숫자가 증가할수록 더 오래 걸릴 수 있기 때문에,'count'가 충분히 큰 경우 어떤 시점에서 improveConcat은 naiveConcat보다 성능이 우수합니다. 하지만'count'를 크게 설정하면 개선 된 Concat은 더 오래 걸립니다. – elgoog