Технология программирования сложных расчетов
Хотелось бы обменятся опытом по следующему интересному вопросу.
Есть некоторый класс задач (поставленный какой-нибудь прикладной наукой), входные и выходные данны четко определены, метод решения также известен. Все что требуется - написать программу для расчета, в которую можно ввести входные данные, выполнить расчет и вывести результаты. В общем все просто, стандартно и банально до безобразия. В принципе даже школьник осилит, если метод не особо замороченный. Также договоримся, что программа пишется под Windows с использова- нием доступных элементов графического интерфейса пользователя, пре- доставляемых как самой ОС, так и средой разработки GUI-приложений. А теперь нюансы... Метод решения может оказаться не особо сложным для понимания, а вот с вычислительной точки зрения очень трудоемким. Соответственно, если расчет "долгий", то окно программы "умирает" на время вычислений, никак не откликаясь на воздействия пользователя. Соответственно, хотелось бы чтобы программа расчета умела следующее: 1) Не "умирать" при выполнении длительных расчетов и быть "отзывчивой". 2) Предоставлять возможность корректно прерывать расчеты в любой мо- мент по желанию пользователя, при этом культурно подчищая все хвосты: освобождая выделенные блоки памяти, закрывая открытые файлы и прочее. 3) Предоставлять возможность следить за текущим состоянием выполняемых расчетов. В простейшем случае - процент завершенности. В более сложных случаях - подробная детализация внутреннего состояния решаемой задачи. У меня, разумеется, за годы выработался свой шаблон для подобных программ, который, разумеется, включает использование отдельных потоков (thread), но там есть свои подводные камни и нюансы, вот о них и хотелось бы поговорить. P.S. Про распараллеливание самого метода решения здесь говорить не будем, это уже совсем отдельная тема... долгая, нудная, многотомная и бесконечная. P.P.S. Да чуть не забыл... Все вышеперечисленные "удобства" ни в коим случае не должны сколь-либо существенно увеличивать общее время решения задачи. Кроме того, главный поток не должен захлёбываться от прорвы Windows message. Ну, и, наконец, обойти все случаи, приводящие к dead-lock (взаимоблокировке). |
Во-первых, программа должна периодически что называется "отдавать управление" (это справедливо для всех ОС, только конкретный механизм может быть разным), про конкретику чуть ниже.
Во-вторых, такая вычислительная программа состоит, очевидно, как минимум из одного цикла (чаще - из N вложенных циклов). Так вот во время каждой итерации (главного цикла) и следует отдавать управление, а также обновлять индикатор прогресса и т.п. В-третьих, целесообразнее такую программу организовать как многопоточную, уж во всяком случае выделив в разные потоки (thread) вычислительную часть и GUI. И наконец, про передачу управления. Если нужно вернуть управление ОС, то в Win32 API это делается посредством ф-ций Sleep(), WaitForXXXX и т.п. Передача управления же от вычислительного потока к GUI-потоку этого же процесса производится путем просматривания очереди сообщений и их направления получателям (по типу того как это делается в ф-ции WinMain). |
Вложений: 1
Что же, прошло достаточно много времени с момента поднятия данной темы.
Хочу поделиться простеньким примером программы, выполняющей "длитель- ные расчеты", послушать мнения и предложения спецов в программировании. Суть самой программы простейший: вводите количество испытаний n и веро- ятность успеха в отдельном испытании p, ну и запускаете расчет, в котором простым итерационным способом проводится n испытаний и подсчитывается количество успехов. Параметр n, целое число в пределах от 0 до 999999999, а p, действительное число (и в качестве разделителя целой и дробной части используется точка, а не запятая), от 0 до 1. Очевидно, при большом n испы- тания и подсчет успехов могут затянуться, поэтому требуется особый подход. Программа написана с использованием традиций объектно-ориентированного программирования и событийно-ориентированного подхода в Delphi, и к этому всему добавлен многопоточный подход со всеми вытекающими особенностями. Исходный код сосредоточен в двух модулях: основном (lm_main.pas) и матема- тическом (lm_math.pas). Исходный код достаточно подробно закомментирован. Основные особенности моего подхода в данной программе: - Математическая обработка выполняется в отдельном потоке SolverThread, ко- торый запускается в обработчике события нажатия кнопки "Пуск". Далее либо он самостоятельно завершается (все испытания проведены) либо прерывается пользователем кнопкой "Стоп", при этом для события завершения потока есть свой отдельный обработчик, где в частности выводятся результаты испытаний. - Математическая обработка реализована не как "отдельно-висящая" функция, а как самостоятельный класс "математического аппарата" (TMathEngine), и он вынесен в отдельный математический модуль программы (это делает программу более структурированной и читабельной). Класс содержит конструктор, дест- руктор, ну и метод (функцию), выполняющую вычисления и испытания в одном цикле. Вычислительный метод (Solve) при вызове из главного модуля программы получает не только параметры n и p, но и два указателя: на специальный флаг, которым можно управлять "извне" для принудительного завершения вычислений, и на специальную структурную переменную, в которую записывается состояние матаппарата, для возможности слежения за "ходом" вычислений "извне". В цикле вычислительного метода на каждой итерации проверяется флаг принудительного завершения, плюс обновляется структурная переменная состояния матаппарата. - Для периодического отображения текущего состояния (хода вычислений) мат- аппарата применен следующий прием. В программе создается специальный тай- мер UpdateTimer, который с периодом 20 миллисекунд срабатывает и операцион- ная система посылает главному окну программы Windows-сообщение WM_TIMER. Это сообщение обрабатывается в главной "оконной" процедуре WndProc, привя- занной к основному окну программы. При обработке сообщений WM_TIMER, про- веряется активен ли данный момент поток матобработки, и если да, то считыва- ется структурная переменная состояния матобработки, вычисляется "прогресс" (доля завершенности) матобработки и обновляется соответ. полоса прогресса. P.S. На всякий случай скажу, что это не лучший пример моего программирова- ния, сам я оцениваю свой подход к реализации сложных расчетов на "четыре". Некоторые проверки и оптимизации я намеренно удалил, чтобы пример был как можно проще и короче, но даже с учетом этого получилось около 450 строк :type: |
Я бы сделал многонитевой демон, выполняющий собственно рассчёты и простую морду к нему на чём-нибудь вроде PyGTK или Vala. IPC - через d-bus. Это заодно позволило бы избежать потери производительности при рассчётах, вызванной странным требованием "программа пишется под Windows" - благо d-bus и по сети отлично работает.
|
Цитата:
Открою секрет (КО): софт разрабатывается исходя из требований заказчика, а не ваших эротических фантазий. И, согласно этим требованиям, где-то в 90 % случаев как раз "программа пишется под Windows". |
|
gav, да я тоже дано заметил, что этому товарисчу присущ технологический экстремизм.
|
Недавно реализовывал простейший клауд на основе самопального протокола аля XML-RPC (разумеется поверх HTTP).
|
Цитата:
Впрочем готов приступить к скрупулёзному исполнению требований сразу после получения первой же платёжки :-D |
Цитата:
Цитата:
|
Цитата:
Просто вопросы в духе "скольковамлет" предполагают некоторую неформальность общения, не находишь? ;-) |
Если тема еще актуальна, то предлагаю обратить внимание на вычисления с помощью графических процессоров (видеокарт), в частности на технологию CUDA. При грамотном распараллеливании можно получить феноменальную производительность.
|
Цитата:
|
Текущее время: 05:26. Часовой пояс GMT +3. |
Powered by vBulletin® Version 3.8.8
Copyright ©2000 - 2024, vBulletin Solutions, Inc. Перевод: zCarot
© 2001—2024, «Аспирантура. Портал аспирантов»