Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Что быстрее: Dictionary vs. Class Fields?

241
14 декабря 2010 года
Sanila_san
1.6K / / 07.06.2005
Сабдж.

Для одной поделки пишу класс со справочными структурами. Там просто постоянные для подстановки в функции. Знаю как минимум два варианта хранения таких постоянных: в словаре и в полях класса. Пример:
Код:
class Command_set:
   
#вариант со словарём
    command_id = {"generic_nack" : 0x80000000,
    "bind_receiver" : 0x00000001,
    "bind_receiver_resp" : 0x80000001,
    "bind_transmitter" : 0x00000002,
    "bind_transmitter_resp" : 0x80000002,
    "query_sm" : 0x00000003,
    "query_sm_resp" : 0x80000003}

    #вариант со свойствами класса
    generic_nack = [0x80, 0x00, 0x00, 0x00 ]


Разные типы здесь потому, что в результате своей работы поделка будет возвращать список. Поэтому в переменной класса сразу указан именно он. Это незначительно изменит логику программы (скажем, где-то можно будет обойтись без преобразований), но по идее отсутствие лишнего пересчёта числа в список ускорит работу. Дело не только в этом.

Вопрос, что быстрее работает: поиск в словаре или поиск к полях класса?
241
14 декабря 2010 года
Sanila_san
1.6K / / 07.06.2005
Утро вечера мудренее.:) После небольшого исследования ответ на поставленный вопрос нашёлся.

Итак, засекаем время выполнения функции:
 
Код:
import time
def timing(f, n, a):
    print f.__name__,
    r = range(n)
    t1 = time.clock()
    for i in r:
        f(a); f(a); f(a); f(a); f(a); f(a); f(a); f(a); f(a); f(a)
    t2 = time.clock()
    print round(t2-t1, 3)

Создаём тупой тестовый класс:
 
Код:
class Testobjext:
    dct = {"var1": 1, "var2": 2, "var3": 3, "var4": 4, "var5": 5, "var6": 6,
           "var7": 7, "var8": 8, "var9": 9, "var10": 10, "var11": 11, "var13": 12,
           "var13": 13, "var14": 14, "var15": 15}
    var1 = 1
    var2 = 2
    var3 = 3
# ...и так далее до...
    var15 = 15

Для чистоты эксперимента две одинаковые функции, возвращающие список, составленный из элементов словаря…
 
Код:
def fobj(emptyarg):
    result = []
    result.append(xobj.dct["var1"])
# и ещё 15 раз случайно взятые значения
    return result
…и полей (переменных) класса:
 
Код:
def fprop(emptyarg):
    result = []
    result.append(xobj.var1)
# тоже ещё 15 раз случайно взятые значения
    return result

Теперь пробуем прогнать стопицот итераций той и другой функции:
 
Код:
for i in range(10000, 110000, 10000):
    print "Attempt on ", i
    timing(fprop, i, 1)
    timing(fobj, i, 1)

Результат изрядно в пользу переменных класса:
Код:
Attempt on  10000
fprop 0.099
fobj 0.273
Attempt on  20000
fprop 0.163
fobj 0.551
Attempt on  30000
fprop 0.243
fobj 0.829
Attempt on  40000
fprop 0.318
fobj 1.089
Attempt on  50000
fprop 0.414
fobj 1.365
Attempt on  60000
fprop 0.493
fobj 1.659
Attempt on  70000
fprop 0.57
fobj 1.925
Attempt on  80000
fprop 0.63
fobj 2.188
Attempt on  90000
fprop 0.727
fobj 2.473
Attempt on  100000
fprop 0.807
fobj 2.848

Число после "Attempt on" следует умножать на 10, поскольку функция timing() последовательно вызывает одну и ту же функцию-аргумент десять раз.

Проще говоря, миллион операций составления 16-элементного списка из переменных класса проходит в 3,5 раза быстрее, чем из элементов словаря, в наилучшем случае разница составляет 2,7 раза в пользу поиска по переменным класса.
87
14 декабря 2010 года
Kogrom
2.7K / / 02.02.2008
Опыт не совсем чистый - словарь сам является полем класса.
Рекомендую ознакомиться с timeit.

Отмечу, что Дэвид Бизли в своей книге про Python пишет, что пользовательские классы и объекты основаны на словарях, поэтому обычно операции поиска изменения или удаления данных в объектах или классах выполняется медленнее, чем непосредственно в словарях.
241
16 декабря 2010 года
Sanila_san
1.6K / / 07.06.2005
В принципе про то, что пользовательские классы основаны на словарях, я в курсе, просто не до конца разобрался, где там быстрее проводится поиск. К тому же это может зависеть и от реализации интерпретатора. У меня, например, PyPy. Что касается timeit, то это хорошая штука. Я использовал самописку timing(), поскольку особо озадачиваться вопросом замера быстродействия не хотелось, а готовый сниппет нашёл у Гвидо ван Россума. :) Пока хочется набросать готовый прототип, и потому уже полировать всем чем можно.

Тогда получается, что мне лучше вовсе не заводить отдельный класс для хранения справочной информации, а объявить словарь недалеко от того места, где он будет вызываться?
87
16 декабря 2010 года
Kogrom
2.7K / / 02.02.2008
Цитата: Sanila_san
Тогда получается, что мне лучше вовсе не заводить отдельный класс для хранения справочной информации, а объявить словарь недалеко от того места, где он будет вызываться?



Не знаю, зависит от ситуации. Я бы, возможно, вообще тупли применил бы. Типа такого:

 
Код:
command_id = (
            generic_nack,
            bind_receiver, bind_receiver_resp, bind_transmitter,
            bind_transmitter_resp, query_sm, query_sm_resp) = (
            0x80000000,
            0x00000001, 0x80000001, 0x00000002,
            0x80000002, 0x00000003, 0x80000003)
           
print command_id[1]
print query_sm_resp

Хотя, это немного на извращение похоже. Ну и раз это константы, то все их бы заглавными буквами написал.
241
18 декабря 2010 года
Sanila_san
1.6K / / 07.06.2005
Попробую и это извращение. Хотя по-моему особо усложнять не надо. Тем более что там мне не обязательно хранить такие вот целочисленные константы, вся работа с данными основана на списках, поэтому и константы мне удобнее хранить не целыми числами, а прямо списками. Таким образом я смог бы избежать штук десять ненужных мне преобразований числа в список за раз.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог