Длительные вычисления
Подготовим два шаблона, которые будут использоваться для длительных вычислениях или при тестировании быстродействия различных алгоритмов.1. Вычисления без подвисания страницы
Чтобы страница браузера не "подвисала", будем вызывать вычисления в таймере после нажатия кнопки run. Создадим объект, который делает следующее:
Начальное значение: Конечное значение: Нажми на кнопкуДля этого вставим в html-страницу два поля редактирования, кнопку и тег жирного шрифта b. У каждого объекта определим уникальное поле id:
Начальное значение: < input type = "text" id = "par1" value = "0" style = "width:3em; text-align:center;" > Конечное значение: < input type = "text" id = "par2" value = "1000000" style = "width:3em; text-align:center;" > < input type = "button" value = "run" onClick = "rn.run(this);" > < b id = "out" >Нажми на кнопку</ b > |
var rn = new Runner( 'out' , [ 'par1' , 'par2' ]); // id объекта вывода и массив входных параметров /**************************************************************************************** * out - id вывода и pars - id параметров */ function Runner(out, pars) { this .period = 100; // длительность вычислений в ms this .wait = 1; // пауза после цикла вычислений в ms this .out = document.getElementById(out); // объект html-страницы для вывода this .btn = null ; // кнопка запуска вычислений if (pars){ this .pars = new Array(pars.length); // массив параметров (если они есть) for (let i=0; i < pars.length; i++) this .pars[i] = Number(document.getElementById(pars[i]).value); } } /**************************************************************************************** * Вызываем из кнопки для запуска или остановки */ Runner. prototype .run = function (btn) { if ( this .timerID === undefined ){ // создаём таймер btn.value = "stop" ; // меняем надпись на кнопке this .btn = btn; // запоминаем кнопку this .init(); // функция инициализации this .timer(); // сразу запускаем вычисление } else this .stop(); // таймер уже запущен, убиваем его } /**************************************************************************************** * Вызываем для остановки таймера */ Runner. prototype .stop = function () { this .timerID = clearTimeout( this .timerID); // убиваем таймер this .btn.value = "run" ; // меняем надпись на кнопке } /**************************************************************************************** * Таймер в котором происходят вычисления */ Runner. prototype .timer = function () { let start = window.performance.now(); while (! this .finish() && window.performance.now() - start < this .period ) this .calc(); // очередной цикл вычислений this .info(); // выводим информацию о вычислениях this .timerID = setTimeout( this .timer.bind( this ), this .wait); if ( this .finish()) // если вычисления закончились, this .stop(); // прекращаем их } /**************************************************************************************** * Инициализация вычислений */ Runner. prototype .init = function () { this .state = this .pars[0]; // задаём начальное состояние } /**************************************************************************************** * Выводим информацию о вычислениях */ Runner. prototype .info = function () { this .out.innerHTML = this .state; } /**************************************************************************************** * Очередной цикл вычислений */ Runner. prototype .calc = function () { this .state++; } /**************************************************************************************** * Kогда прекращать вычисления */ Runner. prototype .finish = function () { return this .state > this .pars[1] } |
JavaScript
Таймер
Выше ключевой является функция setTimeout. Она создаёт таймер, который один раз снова вызывает
функцию timer через 100 ms (второй аргумент функции setTimeout).
Номер таймера сохраняется в свойстве timerID. При удалении таймера функцией clearTimeout
это свойство снова становится равным null. Вся эта деятельность нужна, чтобы страница не подвисала
при вычисления, перерисовывая себя в течении паузы wait.
Таймер
2. Тестирование быстродействия
Для тестирования быстродействия, результаты различных тестов удобно сохранять в табличном виде:
Данные1 | Данные2 | |
---|---|---|
Метод1 | ||
Метод2 |
Для организации подобного табличного "вычислителя" добавим в документ таблицу:
< style > table.right td { color: red; font-family: "Consolas", monospace;} </ style > < center > < table class = "right black" id = "tblOUT" > < tr > < td > < input type = "button" value = "run" style = "width:5em;" onclick = "spd.run(this);" > </ td > < th > Данные1 </ th > < th > Данные2 </ th > </ tr > < tr > < th >Метод1</ th > < td ></ td > < td ></ td > </ tr > < tr > < th >Метод2</ th > < td ></ td > < td ></ td > </ tr > </ table > </ center > |
var spd = new Speed( 'tblOUT' ); function Speed(out) //*** out - id вывода и pars - id параметров { this .wait = 100; // пауза после цикла вычислений в ms this .out = document.getElementById(out); // объект html-страницы для вывода this .btn = null ; // кнопка запуска вычислений } Speed. prototype .run = function (btn) //*** вызываем из кнопки для запуска или остановки { if ( this .timerID === undefined ){ // создаём таймер btn.value = "stop" ; // меняем надпись на кнопке this .btn = btn; // запоминаем кнопку this .init(); // функция инициализации this .timer(); // сразу запускаем вычисление } else this .stop(); // таймер уже запущен, убиваем его } Speed. prototype .stop = function () //*** вызываем для остановки таймера { this .timerID = clearTimeout( this .timerID); // убиваем таймер this .btn.value = "run" ; // меняем надпись на кнопке } Speed. prototype .timer = function () //*** таймер в котором происходят вычисления { this .calc(); // очередной цикл вычислений this .timerID = setTimeout( this .timer.bind( this ), this .wait); if ( this .finish()) // если вычисления закончились, this .stop(); // прекращаем их } Speed. prototype .init = function () { let tbl = this .out, num=0; for (let r=1; r < tbl.rows.length; r++) // очищаем таблицу for (let c=1; c < tbl.rows[r].cells.length; c++){ tbl.rows[r].cells[c].innerText = "" ; num++; } this .state = 0; // номер текущих вычислений this .loop = 0; // количество циклов this .sumTime = new Array(num); this .cntCalc = new Array(num); for (let i = 0; i < num; i++) this .sumTime[i] = this .cntCalc[i] = 0; } Speed. prototype .finish = function () { return this .loop > 10; // останавливаемся поcле 10 циклов } Speed. prototype .calc = function () { let tbl = this .out, r, c, res; let time = window.performance.now(); switch ( this .state){ // последовательно меняем одну из ячеек case 0: res = Math.random(); r=1; c=1; break ; case 1: res = Math.random(); r=1; c=2; break case 2: res = Math.random(); r=2; c=1; break case 3: res = Math.random(); r=2; c=2; break } time = window.performance.now() - time; // время вычислений this .cntCalc[ this .state]++; this .sumTime[ this .state] += time; // вывод времени вычислений tbl.rows[r].cells[c].innerText=( this .sumTime[ this .state]/ this .cntCalc[ this .state]).toFixed(4); this .state++; if ( this .state >= this .sumTime.length){ this .loop++; // прошли всю таблицу this .state = 0; // начинаем по-новой } } |