#arrays #performance #fortran
#массивы #Производительность #fortran
Вопрос:
Прошу прощения, если на этот вопрос есть очевидный ответ, но я не могу правильно сформулировать его, чтобы найти ответ в Интернете.
Предположим, что в Fortran у меня есть массив (> 100 000) действительных чисел. Я буду постоянно обращаться к этому массиву (последовательно) снова и снова на протяжении одного шага схемы временной интеграции. На каждом последующем шаге некоторые элементы этого массива больше не будут нужны. Я не знаю, сколько, это может быть где угодно, от ни одного из них до всех. Мой вопрос:
Что лучше: (1) Проходить через этот массив каждый шаг и копировать оставшиеся элементы, которые мне нужны, в новый массив, даже если может потребоваться удалить только очень небольшой процент, или (2) должен ли у меня быть новый массив целочисленных индексов, который я обновляю каждый раз, чтобы получить доступэтот массив. Я понимаю, что если доступ к памяти является последовательным, он должен быть очень быстрым, и я думаю, что это должно перевесить стоимость копирования массива. С другой стороны, обновление целочисленных индексов будет очень быстрым, но стоимость будет заключаться в том, что данные будут фрагментированы, и доступ к ним будет медленнее.
Или это вопрос такого типа, на который нет однозначного ответа, и мне нужно пойти и протестировать обе методологии, чтобы найти, что лучше для моего приложения?
Комментарии:
1. Всегда лучше показывать реальный код, чем просто длинное описание в словах. Это слишком долго, слишком скучно, слишком двусмысленно. (TLDR)
2. Я подозреваю, что ответ здесь действительно заключается в том, чтобы просто попробовать и посмотреть. По моему опыту, индексирование с помощью поисковых массивов может привести к значительному снижению производительности. Альтернативным подходом было бы реализовать связанный список, который вы можете обновлять по мере удаления элементов, однако я подозреваю, что это также приведет к снижению производительности — но опять же, я думаю, что это действительно зависит от вашего конкретного варианта использования.
Ответ №1:
Трудно сказать заранее, поэтому простым ответом действительно будет * «Измерить!»
Однако некоторые предположения могут помочь с тем, что измерять. Все, что следует из предположения, что код действительно критичен для производительности.
Задержка памяти:
100 тыс. элементов обычно превышают кэш L1 и L2, поэтому локальность памяти будет играть определенную роль. OTOH, линейное сканирование намного лучше, чем выборочный доступ.
Если задержка памяти значительна по сравнению с операциями для каждого элемента, и большинство элементов становятся «неинтересными» после заданного количества итераций, я бы стремился:
- отметьте отдельные элементы как «которые будут пропущены в будущих итерациях»
- уплотняйте память (т.Е. Удаляйте пропускаемые элементы), когда ~ 50% элементов становятся пропускаемыми
(Проверьте вышеуказанные условия: для наивной реализации время одной итерации увеличивается быстрее, чем линейно с увеличением количества элементов?)
Блоки, дружественные к кэшу:
Если задержка памяти является проблемой и можно применить несколько операций к небольшому фрагменту (скажем, 32 КБ данных), сделайте это.
Распараллеливание:
(слон в комнате). Может быть легко добавлен, если вы можете обрабатывать в блоках, удобных для кэша.
Комментарии:
1. Мне очень нравится идея маркировки элементов, а затем очистки при достижении порогового значения. Похоже, это использует лучшее из обоих миров!
2. Хотелось бы увидеть результаты, имеет ли это какое-либо значение вообще и т. Д.!