Как вычислительных физик, я часто работающие программы, которые состоят из многих вложенных для петель . На данный момент, мой внешний цикл циклов через миллионы точек данных и различные внутренние петли изучить десятки тысяч параметров. Я всегда возился с настройками по внутренней петли таким образом, что причиной запуска время колеблется от 10 секунд до 10 недель.
Досадно, что не всегда легко предсказать, как долго эта программа будет запущена после каждого набора изменений. Кроме того, мой код иногда содержит ошибки, которые делают его повесить на неопределенный срок. Если ожидаемое время запуска программы измеряется неделями, это обнадеживает, чтобы регулярные доклады о ходе работы. В противном случае я беспокоюсь, что программа имеет молча упал.
Сначала я просто ударил в печати заявление для внешнего контура, помещены в "если-то заявление, которое активируется только один раз каждые 1000 циклов. Печать заявление использовал время, прошедшее с начала цикла и прогресс, достигнутый оценить оставшееся время. Он выглядел немного как это (плюс некоторые приведения типа ):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | ( NULL ) ; //Grab starting time. start_time = время (NULL); / / Grab времени начала. i = 0 ; i < i_end ; i ++ ) { для (я = 0; <i_end я, я + +) ( i + 1 ) % 1000 == 0 ) { //Only print every 1000 loops. если ((я + 1)% 1000 == 0) (/ / Только печатать каждую 1000 циклов. ( NULL ) ; //Grab current time. CURRENT_TIME = время (NULL); / / Grab текущее время. start_time ; промежутка времени = CURRENT_TIME - start_time; / / Общее время для завершения может быть получено / / Деления промежутка времени фракция уже было сделано. / / После вычета промежутка времени, оставшегося времени / / Слева (в секундах, которое часто запутанным). ( i + 1 ) / ( i_end + 1 ) - timespan ; time_remaining = отрезок времени / (я + 1) / (i_end + 1) - отрезок времени; ( i + 1 ) / i_end * 100 << "% finished, " Суд <<(я + 1) / 100 * i_end <<"% готовой", "seconds remaining." << endl ; <<Time_remaining <<"секунд осталось." <<ЕпсИ; ) j = 0 ; j < j_end ; j ++ ) { для (J = 0; у <j_end; к + +) ( / / Делаем много вещей здесь. ) ) |
Это достаточно, пока я не изменил с настройками внутренней петли таким образом, чтобы увеличить время выполнения драматически. Первое уведомление приняла часов появляется, что я считаю неприемлемо медленно. Тогда я попытался сделать заявление для печати активировать через каждые 10 петель к ускорению уведомление, когда время выполнения очень долго, но это заполнить файл с мегабайт печать заявлений и замедлить программу. Стало ясно, что быстрый хаки собирались требует много текущее обслуживание. Мне нужна система уведомления, которые могут автоматически адаптироваться к краткосрочной и долгосрочной раз бежать.
Я призываю мое решение "Автоматизированная Уведомления". Последняя версия v1.2, который можно скачать здесь .
Особенности:
- Время до первого появится уведомление может управляться отдельно от других уведомлений, и он по умолчанию 10 секунд.
- Времени между всеми последующих уведомлений находятся под контролем переменной, которая определяет целевого интервала между уведомлениями. Фактические интервалы будет в пределах 30% от этой цели (5 минут по умолчанию).
- Минимальное количество (по умолчанию 4) уведомлений будет напечатана предупредить (). Это активируется только при прогнозируемых время выполнения меньше выбрали интервал между уведомления.
- Время, оставшееся напечатан в удобной для восприятия человеком форме с использованием seconds_to_string () функцию. Время сообщили в годы, недели, дни, часы, минуты, секунды. Не более 2 единиц будут напечатаны в каждое выступление уменьшить беспорядок (хотя и это значение можно изменять).
- Печать отчетов заявление от времени, прошедшего в конце цикла, поэтому Оставшееся время можно судить, сколько в отношении цикла фактически взял.
- Внешний цикл может начаться в любой (позитивный! - Должны исправить это!) Индекс, а не только 0, как в примере выше.
- Большинство опций уведомления составляет более каждом цикле, так что несколько петли могут быть настроены по-разному (см. custom_example.cpp).
- Это, вероятно, хорошая идея, чтобы положить код в функции уведомления, что экономит ваши данные на диск, так что, если компьютер перезагрузился, или пропадет напряжение в сети, приложение может быть перезапущен из последнего пункта уведомления. Переменная notification.partial_saves_enabled предназначен для включения этого негласного кодекса, но вы также должны передать новый аргумент, чтобы предупредить () функцию, содержащую данные, которые вы хотите записать на диск.
Требования к кандидату:
- Предназначен для использования в программах на С + +, проверена с помощью G + + компилятор, который поставляется с Ubuntu 8.10 64-бит .
- Ваш внешний цикл должен цикла по многим показателям (в десятки и более). Цикл может начаться в любой индекса вы хотите, но она должна увеличиться на 1 в каждом цикле.
- Требуется iostream, iomanip и векторных библиотек (доступна в Ubuntu по умолчанию).
Программа делится на три файла: common_declarations.hpp содержит определения типов данных и описания функций, common_functions.cpp имеет функцию определения уведомить () и sec2human (), пока example.cpp это всего лишь пример цикла, который использует автоматические уведомления.
Это разделение не является необходимым, но я обнаружил, что это хороший способ организации больших программных проектов. Таким образом, широко используемые функции, которые редко меняется может быть объявлен и определен в общих файлов и составил отдельно от программ, которые просто используют эти функции.
Makefile включены автоматические уведомления составляет в два этапа, чтобы проиллюстрировать этот метод. После добавления многих функций в моей версии общих файлов, первый шаг компиляции занимает почти минуту на моем компьютере. На этом этапе происходит только при общей файлы редактируются, однако, что означает, что редко кому нужна. На втором этапе компиляции, с другой стороны, все более частыми и гораздо быстрее.
Кстати, common_declarations.hpp содержит линии "с использованием имен STD". Я читал , что это плохой практикой программирования, но я не возникнут какие-либо серьезные последствия еще, и это удобно не нужно вводить "зЬй::" Каждый раз, когда я хочу использовать "суда".
Вот что example.cpp выглядит следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | /************************************************* ******* Цель: Эта программа выполняется набор вложенных циклов, что выполнять расчеты бесполезным в течение нескольких минут (точное время зависит от скорости компьютер и пределы вложенных петли). Это означало, чтобы продемонстрировать уведомить () функцию. ************************************************** ******* Автор Тупой ученый Первое письменное: 2009-02-26 Последнее изменение: 2009-03-08 ************************************************** ******/ / / Заголовочный файл "common_declarations.hpp" объявляет о многих / / Функции, константы и типы данных. Для того чтобы использовать / / Функции, объявленные в нем, вы должны указать ссылку этой программы / / С объектного кода с использованием common_functions.cpp. # Включить "common_declarations.hpp" п () ( / / Объявление счетчиков и лимитов на петлях. 0 ,i,j,i_start = 30 ,i_end = 200000 ,j_end = 200000 ; Темп долгое = 0, I, J, i_start = 30, i_end = 200000, j_end = 200000; / / Инициализация переменных для уведомления (). notification_struct уведомления; / / Изменить эту строку, что угодно. "Example loop" ; уведомления. префикс = "Пример цикла"; / / Ваш индекс, начиная, вероятно, будет иной. i_start ; уведомления. starting_index = i_start; / / Ваше окончание индекс также может быть различной. i_end - notification. starting_index ; уведомления. num_loops = i_end - уведомление. starting_index; i = notification. starting_index ; i < i_end ; i ++ ) { для (я = уведомления. starting_index; <i_end я, я + +) ( / / Печать Периодически оставшееся время. ; уведомление (извещение, я); j = 0 ; j < j_end ; j ++ ) { для (J = 0; у <j_end; к + +) ( / / Совершенно бесполезно расчета. ( i * j * j * j - 2 * i + 3 * j ) ; Темп + = (я * у * у * J - 2 * я + 3 * J); ) / / Конец вложенного цикла. ) / / Конец внешнего цикла. / / Время записи в конце программы. time ( NULL ) ; уведомления. end_time = время (NULL); notification. end_time - notification. start_time ; уведомления. time_total = уведомления. end_time - уведомление. start_time; notification. prefix << " took " Суд <<уведомления. префикс <<"принял" notification. time_total ) << endl ; <<Seconds_to_string (notification. time_total) <<епсИ; / / Если температура не используется где-то, эта программа имеет / / 0 сек. Я думаю, что результат-O2 / / Флаг, заметив, что выше петли не нужны. Темп возвращения; ) |
При запуске он производит вывод, который выглядит следующим образом (отметим, что первая строка появится в течение нескольких секунд, и последующих уведомлений на 25% друг от друга, так как расчетное время запуска этой программы меньше, чем по умолчанию интервал):
1 2 3 4 5 6 | Пример цикла на 8,20%. Осталось: 1 минуту 52 секунд Пример цикла на 33,20%. Осталось: 1 минуту 20 секунд Пример цикла на 58,19%. Осталось: 51 секунд Пример цикла на 83,19%. Осталось: 20 секунд Пример цикла взял 2 минуты 1 секунду ` |
Я изменил границы петли, добавив 4 нулей каждая i_end и j_end, но первая строка появилась еще в течение нескольких секунд:
1 2 | Пример цикла на 0,00%. Осталось: 285 лет, 10 недель ` |
Разумеется, я не стал ждать, что один и до конца. Но дело в том, что я быстро знал, что я умру старых веков до возраста это было сделано. Кстати, я попробовал добавить еще несколько нулей j_end и это вызвало первое уведомление принять раздражающе долгое время появляться. Это происходит потому, что внешний цикл занимает много времени, чтобы прирост только один раз. Я еще не знаю, как я хочу, чтобы решить эту проблему.
Автоматизированная Уведомления является свободным программным обеспечением под лицензией GPLv3 , а не ЦК лицензию , что остальная часть сайта использует. Если кто-то замечает какое-либо ошибки или какие-либо предложения по повышению эффективности использования автоматических оповещений, пожалуйста, дайте мне знать в комментариях ниже. Я также хотела бы видеть, как другие решить эту проблему, независимо от языка, она написана дюйма
История версий
v1.2 - 2009-03-08 - настройки по умолчанию упрощенный сократить example.cpp, добавил custom_example.cpp.
v1.1 - 2009-02-27 - Заменяется макс и мин с интервалом target_interval.
v1.0 - 2009-02-26 - Первый релиз.
Последнее изменение 2 августа 2009

























































Я удивлен, что вы не использовали прерыванием таймера. Нет накладные расходы, а цикл работает и точный контроль интервала выборки. Просто необходим некоторый способ получить цикле переменных в обработчик прерываний и результаты из.
Не использовал, потому что я никогда не слышал об этом раньше. Спасибо, я буду смотреть в него.
"Производства" версия этой функции принимает структуру с несколькими ГБ данных и autosaves его на диск. Я интересно, если прерыванием таймера может быть отправлено, что много данных в прозрачной моды? То есть вся структура должна быть отправлены через ссылки в качестве единственного аргумента без локальной копии данных (он едва помещается в памяти ранее.)
Кроме того, функция должна быть призваны в том, что точное место в коде, а не во внутреннем цикле, в противном случае функция автосохранения не будет работать корректно. Если все это возможно с помощью таймера прерывания, кто-то нравиться мне точку пример кода.
(Ред. внимание: на этот комментарий был первоначально размещен здесь .)
Почему? Это просто значит, я должен открыть больше файлов, когда я хочу, чтобы выполнить обширную обслуживание по программе.
Компиляция, безусловно, быстрее, если можно перейти только 1 из 100 с таким же количеством файлов, но я решил создать две основные исходные файлы: во-первых редко редактируются и большой (30К линии), а второй редактируется в десятки раз в день и только 1k линий. Makefile собирает большой файл в объектный код, который связывается с объектом код с небольшой файл. Большой файл после этого лишь составлены, если изменения даты подачи большой источник новее, чем большой файл объекта. Еще раз для компиляции большого файла только ~ 10 секунд, если нетбук оптимизации инвалидов, а также не ясно, что мои компиляции раз будет расти быстрее, чем скорость процессора будет. (Особенно, если параллельно г + + никогда не получает достойной.)
Я полагаю, можно сказать, что код сегментация помогает обеспечить соблюдение "некоторые взаимосвязи между функциями" принципа. (Или как там оно официально называется: о том, что функции должны взаимодействовать лишь в нескольких четко определенных путей.) Этот идеал теоретически привлекательным, но, кажется раздражает реализации без учета редким исключением. Я не хочу, чтобы изменить полезным ориентиром в жесткую закон, который, вероятно, просто медленно меня.
Я также написать код самостоятельно, так силу причин, связанных программирования команды не соответствующих действительности. Хорошая система управления версиями Mercurial, как должно свести к минимуму эти вопросы так или иначе.
Есть ли реальный (т.е. производительность, масштабируемость) причин отказаться от такого подхода, и положить начало новой функции в отдельных файлах? Я не профессиональный программист, так что я могу что-то упустил, что компьютерные науки кандидат будет рассматривать очевидные и убедительные ...
Поскольку у вас есть лицензия код под GPL (так что в основном приветствовать Вас или, по крайней мере, не виду другие исследования и поделиться код), затем код управляемость приятно иметь что может быть достигнуто путем модульности .
Главное помнить, чтобы разделить код согласно тому, что он (логическое разделение). Чтобы быть честным, я не посмотрел на свой код так, может быть, это не относится в данном случае (возможно, один очень большой файл оправдано).
Сказав это, в конце дня Есть нет жестких законов, просто созданы руководящие принципы опыт и много ошибок:)
Отлично точек. Спасибо за статью.