В Python быстрый способ преобразования байтового массива в массив кортежей (без использования NumPy) - PullRequest
0 голосов
/ 26 апреля 2019

Мне нужно ускорить следующий код: -

index = 0
WIDTH = 1920
HEIGHT = 1080
for o in xrange(WIDTH * HEIGHT):
    outbuf[o] = (buffer[index], buffer[index+1], buffer[index+2])
    index += 3

Который преобразует bytearray в массив кортежей, но слишком медленный, есть ли способ сделать его быстрее без использования numpy.

1 Ответ

0 голосов
/ 27 апреля 2019

Строительство outbuf по рецепту группировщика из itertools почти в два раза быстрее на моей машине.

Это функция группирования из документов:

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

Этот скрипт сравнивает время для функции в вопросе, используя grouper для заполнения outbuf и используя grouper для возврата outbuf вместо заполнения внешнего списка. Самый быстрый способ - вернуть outbuf из функции.

from itertools import izip_longest
import random
import sys
import timeit

WIDTH = 1920
HEIGHT = 1080


buffer_ = bytearray(random.randint(0, 255) for _ in xrange(WIDTH * HEIGHT * 3))

# Function from the question
def extract(buffer_):
    index = 0
    for o in xrange(WIDTH * HEIGHT):
        outbuf[o] = (buffer_[index], buffer_[index+1], buffer_[index+2])
        index += 3


def grouper(iterable, n, fillvalue=None):
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)


# Use grouper with external outbuf
def grouper_extract(buffer_):
    groups = grouper(buffer_, 3)
    for o in xrange(WIDTH * HEIGHT):
        outbuf[o] = next(groups)


# Return a list using grouper
def grouper_list(buffer_):
    return list(grouper(buffer_, 3))


if __name__ == '__main__':
    # Set number of timeit repetitions.
    try:
        number = int(sys.argv[1])
    except IndexError:
        number = 50
    outbuf = [0 for _ in xrange(WIDTH * HEIGHT * 3)]
    print 'OP function'
    print timeit.timeit(setup="from __main__ import extract, outbuf, buffer_",
                        stmt="extract(buffer_)", number=number)
    print
    print 'Fill external outbuf with grouper'
    print timeit.timeit(setup="from __main__ import grouper_extract, outbuf, buffer_",
                        stmt="grouper_extract(buffer_)", number=number)
    print
    print 'Return outbuf using grouper'
    print timeit.timeit(setup="from __main__ import grouper_list, buffer_",
                        stmt="outbuf = grouper_list(buffer_)", number=number)
    print

Вот время для 50 повторений каждого подхода:

OP function
39.3345730305

Fill external outbuf with grouper
30.0249710083

Return outbuf using grouper
20.357350111
...