source

반복기를 목록으로 변환하는 가장 빠른 방법

manycodes 2023. 1. 9. 21:16
반응형

반복기를 목록으로 변환하는 가장 빠른 방법

가지고 있다iterator오브젝트, 반복자에 의해 반환된 오브젝트의 목록을 얻기 위해 리스트 이해보다 더 빠르고, 더 낫고, 더 정확한 것이 있는가?

user_list = [user for user in user_iterator]
list(your_iterator)

python 3.5를 사용할 수 있습니다.*반복 가능한 포장 풀기 연산자:

user_list = [*your_iterator]

하지만 버마적인 방법은:

user_list  = list(your_iterator)

@Robino는 이치에 맞는 테스트를 추가할 것을 제안하고 있었습니다.따라서 반복기를 목록으로 변환하기 위한 3가지 방법(아마 가장 많이 사용되는 방법) 사이의 간단한 벤치마크를 다음에 제시하겠습니다.

  1. 유형 생성자별

    list(my_iterator)

  2. 포장을 풀어서

    [*my_iterator]

  3. 목록 이해 사용

    [e for e in my_iterator]

simple_bechmark 라이브러리를 사용하고 있습니다.

from simple_benchmark import BenchmarkBuilder
from heapq import nsmallest

b = BenchmarkBuilder()

@b.add_function()
def convert_by_type_constructor(size):
    list(iter(range(size)))

@b.add_function()
def convert_by_list_comprehension(size):
    [e for e in iter(range(size))]

@b.add_function()
def convert_by_unpacking(size):
    [*iter(range(size))]


@b.add_arguments('Convert an iterator to a list')
def argument_provider():
    for exp in range(2, 22):
        size = 2**exp
        yield size, size

r = b.run()
r.plot()

여기에 이미지 설명 입력

컨스트럭터에 의한 변환과 언팩에 의한 변환을 구별하는 것은 매우 어렵기 때문에 리스트 이해에 의한 변환은 가장 느린 접근법입니다.


또한 다음과 같은 간단한 스크립트를 사용하여 다양한 Python 버전(3.6, 3.7, 3.8, 3.9)에 걸쳐 테스트하고 있습니다.

import argparse
import timeit

parser = argparse.ArgumentParser(
    description='Test convert iterator to list')
parser.add_argument(
    '--size', help='The number of elements from iterator')

args = parser.parse_args()

size = int(args.size)
repeat_number = 10000

# do not wait too much if the size is too big
if size > 10000:
    repeat_number = 100


def test_convert_by_type_constructor():
    list(iter(range(size)))


def test_convert_by_list_comprehension():
    [e for e in iter(range(size))]


def test_convert_by_unpacking():
    [*iter(range(size))]


def get_avg_time_in_ms(func):
    avg_time = timeit.timeit(func, number=repeat_number) * 1000 / repeat_number
    return round(avg_time, 6)


funcs = [test_convert_by_type_constructor,
         test_convert_by_unpacking, test_convert_by_list_comprehension]

print(*map(get_avg_time_in_ms, funcs))

스크립트는 Jupyter 노트북(또는 스크립트)의 서브프로세스를 통해 실행되며 size 파라미터는 명령줄 인수를 통해 전달되며 스크립트 결과는 표준 출력에서 가져옵니다.

from subprocess import PIPE, run

import pandas

simple_data = {'constructor': [], 'unpacking': [], 'comprehension': [],
        'size': [], 'python version': []}


size_test = 100, 1000, 10_000, 100_000, 1_000_000
for version in ['3.6', '3.7', '3.8', '3.9']:
    print('test for python', version)
    for size in size_test:
        command = [f'python{version}', 'perf_test_convert_iterator.py', f'--size={size}']
        result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True)
        constructor, unpacking,  comprehension = result.stdout.split()
        
        simple_data['constructor'].append(float(constructor))
        simple_data['unpacking'].append(float(unpacking))
        simple_data['comprehension'].append(float(comprehension))
        simple_data['python version'].append(version)
        simple_data['size'].append(size)

df_ = pandas.DataFrame(simple_data)
df_

여기에 이미지 설명 입력

제 노트북은 여기서 다 받으실 수 있습니다.

대부분의 경우 테스트에서는 포장을 푸는 것이 더 빠르지만, 그 차이가 너무 작기 때문에 실행에서 다른 실행으로 결과가 달라질 수 있습니다.다시 말씀드리지만, 이해 접근법이 가장 느립니다. 다른 두 가지 방법은 최대 60% 더 빠릅니다.

언급URL : https://stackoverflow.com/questions/3790848/fastest-way-to-convert-an-iterator-to-a-list

반응형