python: deque vs list performance comparison

后端 未结 4 1935
眼角桃花
眼角桃花 2020-11-29 20:59

In python docs I can see that deque is a special collection highly optimized for poping/adding items from left or right sides. E.g. documentation says:

<
4条回答
  •  心在旅途
    2020-11-29 21:27

    I found my way to this question and thought I'd offer up an example with a little context.
    A classic use-case for using a Deque might be rotating/shifting elements in a collection because (as others have mentioned), you get very good (O(1)) complexity for push/pop operations on both ends because these operations are just moving references around as opposed to a list which has to physically move objects around in memory.

    So here are 2 very similar-looking implementations of a rotate-left function:

    def rotate_with_list(items, n):
        l = list(items)
        for _ in range(n):
            l.append(l.pop(0))
        return l
    
    from collections import deque
    def rotate_with_deque(items, n):
        d = deque(items)
        for _ in range(n):
            d.append(d.popleft())
        return d
    

    Note: This is such a common use of a deque that the deque has a built-in rotate method, but I'm doing it manually here for the sake of visual comparison.

    Now let's %timeit.

    In [1]: def rotate_with_list(items, n):
       ...:     l = list(items)
       ...:     for _ in range(n):
       ...:         l.append(l.pop(0))
       ...:     return l
       ...: 
       ...: from collections import deque
       ...: def rotate_with_deque(items, n):
       ...:     d = deque(items)
       ...:     for _ in range(n):
       ...:         d.append(d.popleft())
       ...:     return d
       ...: 
    
    In [2]: items = range(100000)
    
    In [3]: %timeit rotate_with_list(items, 800)
    100 loops, best of 3: 17.8 ms per loop
    
    In [4]: %timeit rotate_with_deque(items, 800)
    The slowest run took 5.89 times longer than the fastest. This could mean that an intermediate result is being cached.
    1000 loops, best of 3: 527 µs per loop
    
    In [5]: %timeit rotate_with_list(items, 8000)
    10 loops, best of 3: 174 ms per loop
    
    In [6]: %timeit rotate_with_deque(items, 8000)
    The slowest run took 8.99 times longer than the fastest. This could mean that an intermediate result is being cached.
    1000 loops, best of 3: 1.1 ms per loop
    
    In [7]: more_items = range(10000000)
    
    In [8]: %timeit rotate_with_list(more_items, 800)
    1 loop, best of 3: 4.59 s per loop
    
    In [9]: %timeit rotate_with_deque(more_items, 800)
    10 loops, best of 3: 109 ms per loop
    

    Pretty interesting how both data structures expose an eerily similar interface but have drastically different performance :)

提交回复
热议问题