Что быстрее? глобальные или локальные переменные?

 

Здравствуйте,

вопрос к разработчикам самого Metаtrader  или разработчикам советников с большим опытом.

При оптимизации советников большое значение имеет скорость работы функций.

1) Какие переменные лучше использовать в них, глобальные или локальные?

2) Читал по языку Си, что локальные переменные хранятся в регистрах процессора, следовательно работа с ними быстрее. Так ли это в Metаtrader 4 и 5?

3) Понятно, что без глобальных переменных не обойтись, например в функции глобальная переменная используется 10 раз (арифм. операции, сравнение и т.п.). Лучше ли будет скопировать 1 раз ее в локальную, и далее 10 раз воспользоваться уже локальной переменной?

4) Еще не ясно, с массивами, где-то читал, что работа с ними медленнее, чем с несколькими переменными. Так ли это?

5) константы глобального уровня и переменные глобального уровня, равны по скорости?

------ Полученные ответы из обсуждения ---------------

1) глобальные быстрее (оказывают заметное влияние, если количество операций с ними - несколько тысяч. Если единицы, как в большинстве советников, то влияние - ничтожное.)

3) нет

4) если массив динамический и приходится постоянно пополнять его, то его переразмер занимает много времени. Лучше использовать массивы с заранее определенным размером.

 
elibrarius:

Здравствуйте,

вопрос к разработчикам с большим опытом или к разработчикам.

При оптимизации советников большое значение имеет скорость работы функций.

1) Какие переменные лучше использовать в них, глобальные или локальные?

2) Читал по языку Си, что локальные переменные хранятся в регистрах процессора, следовательно работа с ними быстрее. Так ли это в Metаtrader 4 и 5?

3) Понятно, что без глобальных переменных не обойтись, например в функции глобальная переменная используется 10 раз (арифм. операции, сравнение и т.п.). Лучше ли будет скопировать 1 раз ее в локальную, и далее 10 раз воспользоваться уже локальной переменной?

4) Еще не ясно, с массивами, где-то читал, что они очень медленные в работе. Так ли это?

2. Спецификация языка Си не определяет положение локальных переменных в регистрах. Тем более регистров процессора все равно на все переменные не хватит. В Си есть ключевое слово 'register', но и оно не подразумевает, что переменная должна разместиться в одном из регистров процессора. Это слово просто дает компилятору указание, что необходимо попытаться прооптимизировать работу с ней особенно тчательно.

4. Нет, не так. Массивы предоставляют самый быстрый способ работы с группированными данными. К каждому элементу можно обратиться напрямую, используя его индекс (адресную арифметику по сути). Но у массивов есть существенный недостаток: операции по вставке/изменению размера очень, очень ресурсоемки. Так, если вы накапливаете данные в массив и знаете, что в конце работы программы величина этих данных не превысит 1 000 000 элементов, то лучше сразу выделить все необходимую память, чем поэлементно вставлять новые значения в массив. Такая поэлементная вставка будет раз за разом переразмечать емкость массива, что снизит производительность на порядок.  Этот тип данных представлен в стандартной библиотеки классами CArray 

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

Есть еще один тип организации данных: словарь или хеш. Он представляет из себя некое хранилище данных, к каждому элементу которого можно обратиться указав вместо индекса сам объект к которому требуется доступ. Например Hash["Коля","Петя","Вася","Саша","Катя"]; sting my_name = Hash["Вася"]; Hash очень быстро найден значение "Вася" и вернет его переменной my_name. Его организация напоминает что-то среднее между списком и массивом, а по производительности он скорее близок к массивам, хотя и уступает им в скорости. К сожалению в стандартной библиотеке этот тип данных не представлен. 

Основных видов памяти в компьютере два: это Стек и Куча. Стек считается более быстрым чем куча. В нем размещаются локальные переменные. В куче размещаются динамические объекты. В целом очень многое зависит от языка программирования. Как сделано конкретно в MQL5 могут ответить только разработчики. В C# например, в стеке размещаются значимые типы: int, double, byte, struct... а в куче ссылочные, т.е. все объекты типа class. В С++ такого жесткого разделения нет. Где и как будет размещаться объект определяет компилятор.

По сабжу: как разработчик Вы должны оптимизировать приложение в зависимости от его задачи. Так например, если Вы активно формируете некоторый массив данных, вставляете и сортируете элементы внутри него, то Вы должны  сознательно выбрать в качестве хранилища данных более медленный CList, потому что применительно к Вашей задаче он будет гораздо более эффективней чем более быстрый CArray и т.д.

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

 
C-4:

Есть еще один тип организации данных: словарь или хеш. Он представляет из себя некое хранилище данных, к каждому элементу которого можно обратиться указав вместо индекса сам объект к которому требуется доступ. Например Hash["Коля","Петя","Вася","Саша","Катя"]; sting my_name = Hash["Вася"]; Hash очень быстро найден значение "Вася" и вернет его переменной my_name. Его организация напоминает что-то среднее между списком и массивом, а по производительности он скорее близок к массивам, хотя и уступает им в скорости. К сожалению в стандартной библиотеке этот тип данных не представлен.

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

Действительно очень странно что в стандартной библиотеке этого нет. A перечисления (enumeration) есть?

Ассоциативный массив — Википедия
  • ru.wikipedia.org
Ассоциативный массив (словарь) — абстрактный тип данных (интерфейс к хранилищу данных), позволяющий хранить пары вида «(ключ, значение)» и поддерживающий операции добавления пары, а также поиска и удаления пары по ключу: Предполагается, что ассоциативный массив не может хранить две пары с одинаковыми ключами. В паре значение называется...
 
"Преждевременная оптимизация — это корень всех бед" (c) Дональд Кнут

Сначала нормальный код, а потом профайлером по нему.
 
Roffild:
Сначала нормальный код, а потом профайлером по нему.
Яро плюсую.
 
C-4:

Есть еще один тип организации данных: словарь или хеш. Он представляет из себя некое хранилище данных, к каждому элементу которого можно обратиться указав вместо индекса сам объект к которому требуется доступ. Например Hash["Коля","Петя","Вася","Саша","Катя"]; sting my_name = Hash["Вася"]; Hash очень быстро найден значение "Вася" и вернет его переменной my_name. Его организация напоминает что-то среднее между списком и массивом, а по производительности он скорее близок к массивам, хотя и уступает им в скорости. К сожалению в стандартной библиотеке этот тип данных не представлен.

Не ну вот зачем писать то в чем я так понимаю ниже планки нуля? Словарь и хеш-карта это две абсолютно разных сущности. В С++ есть map и hashmap.
 
TheXpert:
Не ну вот зачем писать то в чем я так понимаю ниже планки нуля? Словарь и хеш-карта это две абсолютно разных сущности. В С++ есть map и hashmap.
Словарь можно реализовать на основе хеша, а можно и другим методом. Но если делать все по-взрослому, то хеширующая функция в словаре по-любому понадобиться, ибо как иначе ты сможешь гарантировать уникальность объекта и его эффективную сортировку? А вообще чрезмерно умничать не стоит. Конечному пользователю (т.е. нам программистам) не важна фактическая реализация алгоритма, а важны лишь те свойства, которые он дает.
 
C-4:

В подавляющем большинстве случаев хватает мапы, которая реализована r-b деревом.

Я не умничаю чрезмерно, я другим не даю этого делать.

 
TheXpert:

В подавляющем большинстве случаев хватает мапы, которая реализована r-b деревом.

Я не умничаю чрезмерно, я другим не даю этого делать.

Да нет, умничаешь и зафлуживаешь ветку здесь ты. Реализаций словаря может быть несколько. Но я написал только о той, что известна лично мне. Я не работаю с С++ и не знаю что такое "мапы", но знаю что в C# стандартный Dictionary реализован на основе хеш-таблицы поэтому мое сравнение с хештаблицей предельно корректно. Словарь в .Net содержит пару "ключ - значение", где уникальность ключа гарантирует хеш функция. Хеш таблица содержит только уникальные объекты, уникальность которых гарантируется той же хеш функцией. Сама хеш функция в развитых средах может быть переопределена наследником. Так в C# поведение хеш функции различно в зависимости от того, имеем ли мы дело с ссылочным или значимым типом...

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

Под капотом у Dictionary и ConcurrentDictionary
Под капотом у Dictionary и ConcurrentDictionary
  • habrahabr.ru
Некоторое время назад, я решил, что хочу знать больше подробностей о работе многопоточности в .NET и что я уделял этому незаслуженно мало внимания в прошлом. Информации на эту тему великое множество (отправной точкой я для себя выбрал этот раздел книги «C# in a nutshell»), но, как оказалось, только малая часть ресурсов пытаются объяснить что-то...
 
C-4:

Перечитал, приношу извинения. У меня таки выражение стандартная библиотека никак не ассоциируется со здешней стандартной. Автоматом подумал на STL отсюда и непонятки.

А шарповский dictionary как раз на hashmap и сделан. И если пишешь про dictionary, то и пиши про него и c#, а не про словарь и вообще.

Документация по MQL5: Стандартная библиотека
Документация по MQL5: Стандартная библиотека
  • www.mql5.com
Стандартная библиотека - Документация по MQL5
 
TheXpert:

Перечитал, приношу извинения. У меня таки выражение стандартная библиотека никак не ассоциируется со здешней стандартной. Автоматом подумал на STL отсюда и непонятки.

А шарповский dictionary как раз на hashmap и сделан. И если пишешь про dictionary, то и пиши про него и c#, а не про словарь и вообще.

Как всегда, разность контекста. Ладно проехали)

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

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            //Ассциируем с каждой личностью ее рейтинг на MQL5:
            Dictionary<CPerson, int> DictionaryRaiting = new Dictionary<CPerson, int>();
            DictionaryRaiting.Add(new CPerson("Вася"), 1910);
            //А теперь побезобразничаем и создадим копии личности:
            DictionaryRaiting.Add(new CPerson("Вася"), 1910);
            DictionaryRaiting.Add(new CPerson("Вася"), 1910);
            DictionaryRaiting.Add(new CPerson("Вася"), 1910);
            DictionaryRaiting.Add(new CPerson("Вася"), 1910);
            DictionaryRaiting.Add(new CPerson("Вася"), 1910);
            DictionaryRaiting.Add(new CPerson("Вася"), 1910);
            foreach (var person in DictionaryRaiting)
                Console.WriteLine("Личность: {0}; Оценка:{1}", person.Key.Name, person.Value);
            Console.ReadKey();
            //??? - Как же так? Словарь позволяет хранить одинаковые элементы? Ужасть!!!!
            //Попробуем еще раз, на этот раз с SPerson - полной копией CPerson но только...
            Dictionary<SPerson, int> DictionaryRaiting2 = new Dictionary<SPerson, int>();
            DictionaryRaiting2.Add(new SPerson("TheExpert"), 7243);
            //Наученный опытом созданим коллекцию одинаковых SPerson по аналогии с CPerson:
            DictionaryRaiting2.Add(new SPerson("TheExpert"), 7243);
            //....
            // Crashed!!!!!!!
        }
    }

    /// <summary>
    /// Личность
    /// </summary>
    class CPerson
    {
        public CPerson(string name)
        {
            mName = name;
        }

        public string Name
        {
            get { return mName; } 
        }
        /// <summary>
        /// Внутреннее имя человека.
        /// </summary>
        private string mName;
    }

    /// <summary>
    /// Еще одна личность, (найди 10 отличий от CPerson))))
    /// </summary>
    struct SPerson
    {
        public SPerson(string name)
        {
            mName = name;
        }

        public string Name
        {
            get { return mName; }
        }
        /// <summary>
        /// Внутреннее имя человека.
        /// </summary>
        private string mName;
    }
}

 Этот пример благополучно выполниться до метки Crashed явно указывая нам, что два и более абсолютно одинаковых объекта (конкретно "Вася с рейтингом 1710") могут благополучно находиться в словаре, где по идеи каждый ключ должен быть уникальным. В то же время при попытке загнать объект "TheExpert  с рейтингом 7243" уже при второй попытке приведут к исключению времени исполнения. В чем же дело? 

А дело здесь в том, что словарь как и хеш таблица использует для идентификации объекта функцию GetHeshCode(). В первом случае эта функция не переопределяется и наследуется от базового объекта Object всех классов как есть. Если хеши не равны, то объекты разные и могут существовать в одной уникальной коллекции. Но дело в том что сама хеш функция использует понятие равенства объектов. А по умолчанию ссылочные объекты считается равными, если ссылаются на один и тот же кусок памяти, а этого-то и нет в данном примере! Ведь каждый раз когда мы создаем объект CPerson оператором new, он создается в новом сегменте памяти, а значит все-таки это разные объекты!

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

Причина обращения: