Быстрый поиск атрибутов на языке с динамической типизацией?

В настоящее время я разрабатываю язык с динамической типизацией.

Одна из основных проблем, с которыми я сталкиваюсь во время разработки, - это быстрый поиск символов во время выполнения.

Для общих, бесплатных глобальных и локальных символов я просто индексирую их и позволяю каждой области (глобальной или локальной) хранить массив символов и быстро искать их с помощью индекса. Я очень доволен таким подходом.

Однако с атрибутами в объектах проблема намного сложнее. Я не могу использовать для них ту же схему индексации, потому что я не знаю, к какому объекту я обращаюсь в данный момент, поэтому я не знаю, какой индекс использовать!

Вот пример на Python, который отражает то, что я хочу работать на моем языке:

class A:
    def __init__(self):
        self.a = 10
        self.c = 30

class B:
    def __init__(self):
        self.c = 20

def test():
    if random():
        foo = A()
    else:
        foo = B()
    # There could even be an eval here that sets foo
    # to something different or removes attribute c from foo.
    print foo.c

Кто-нибудь знает какие-нибудь хитрые приемы для быстрого поиска? Я знаю о хэш-картах и ​​растянутых деревьях, поэтому мне интересно, есть ли какие-то способы сделать это так же эффективно, как мой другой поиск.


person monoceres    schedule 31.05.2013    source источник
comment
Включает ли ваш язык все остальные вещи, которые в целом усложняют эту задачу, например, добавление и удаление атрибутов объекта во время его существования и _1 _ / _ 2 _ / _ 3_?   -  person    schedule 31.05.2013
comment
Да! Я не знаю о методах * attr, но определенно можно будет изменить объект и атрибуты во время его жизни.   -  person monoceres    schedule 31.05.2013


Ответы (2)


Как только вы достигли точки, когда поиск свойств в хеш-таблице не выполняется достаточно быстро, следующим стандартным шагом будет встроенное кеширование. Вы можете сделать это на языках JIT или даже в компиляторах или интерпретаторах байт-кода, хотя там это, кажется, менее распространено.

Если форма ваших объектов может со временем меняться (т. Е. Вы можете добавлять новые свойства во время выполнения), вы, вероятно, в конечном итоге сделаете что-то похожее на скрытые классы.

person munificent    schedule 01.06.2013
comment
Очень полезные ссылки. Схема встроенного кеширования действительно умна! Я думаю, что даже при смене объектов это может быть победителем. Всякий раз, когда объект изменяется, вы можете просто пометить объект как мертвый, чтобы все текущие кеши объекта стали недействительными! - person monoceres; 01.06.2013
comment
Ах, я знаю, что кое-что забыл. У меня есть сомнения по поводу применения встроенного кеширования к интерпретаторам. Я думаю, что кеш метода MRI (только для методов) делает нечто подобное, исправляя инструкции байт-кода. Мне кажется, что это единственный способ добиться кеширования без огромных дополнительных затрат. Однако это общеизвестно неэффективно. Это может быть связано с конкретной реализацией и привычками программистов Ruby. - person ; 01.06.2013

Метод, известный как карты, может сохранять значения для каждого атрибут в компактном массиве. Информация о том, какое имя атрибута соответствует какому индексу, поддерживается во вспомогательной структуре данных (одноименной карте), поэтому вы не сразу получаете выигрыш в производительности (хотя он использует память более эффективно, если многие объекты совместно используют набор атрибутов). С помощью JIT-компилятора вы можете сделать карту постоянным и постоянным поиском, поэтому окончательный машинный код может использовать постоянные смещения в массиве атрибутов (для постоянных имен атрибутов).

В интерпретаторе (я предполагаю, что это байтовый код) все намного сложнее, потому что у вас не так много возможностей специализировать код для определенных объектов. Однако у меня есть идея превратить имена атрибутов в составные ключи. Поддерживайте глобальное сопоставление, назначающее интегральные идентификаторы именам атрибутов. При добавлении нового байтового кода в виртуальную машину (загрузка с диска или компиляция в памяти) просканируйте строки, используемые в качестве атрибутов, и замените их соответствующим идентификатором, создав новый идентификатор, если строка не была видна раньше. Вместо хранения хэш-таблиц или аналогичных сопоставлений для каждого объекта - или на карте, если вы используете карты - теперь вы можете использовать разреженные массивы, которые, надеюсь, более компактны и быстрее работают.

У меня не было изменений, чтобы реализовать и протестировать это, и вам все еще нужен разреженный массив. Если вы не хотите, чтобы все объекты (или карты) занимали столько слов памяти, сколько существует различных имен атрибутов во всей программе, то есть. По крайней мере, вы можете заменить строковые хеш-таблицы целочисленными хеш-таблицами. Просто настроив хэш-таблицу для идентификаторов в качестве ключей, вы можете сделать несколько оптимизаций: не вызывать хеш-функцию (использовать идентификатор в качестве хеша), удалить некоторые косвенные ссылки и, следовательно, промахи в кеше, сэкономить сложность работы с патологически плохим хешем. функции и т. д.

person Community    schedule 31.05.2013
comment
Это очень интересно! На самом деле это байт-код, и ваша вторая идея звучит великолепно! На самом деле я сам придумал что-то подобное, но, поскольку я не знал о структуре данных разреженного массива, я просто подумал, что требования к пространству будут слишком большими! Теперь я могу переоценить это :) - person monoceres; 01.06.2013