может быть, было бы разумнее иметь только один таймер, работающий в этом отношении ...
насколько я знаю, работающему таймеру нужна целая нить ...
чтобы поместить его в псевдокод, основной код потока Timer выглядит примерно так ...
while (input.isEmpty()) {
wait(interval);
output.add({timerId:thisId, tickId: tickId++});
}
вывод, являющийся удалением из очереди, основной поток (который выполняет ABC) проверяет каждый сейчас и потом ... имея много таймеров, у вас будет много потоков, что является ненужными издержками ... также, для каждого события, сообщение отправка из таймера в основной поток должна быть извлечена из очереди, что дорого, так как это должно быть потокобезопасно ... и затем должен быть найден соответствующий таймер, должно быть создано событие таймера (выделение также довольно дорого), а затем отправлен, что также является вопросом нескольких звонков ...
так что попробуйте иметь ОДИН таймер или использовать setInterval ... также, учтите, что модель Event во флэш-памяти довольно хороша, но дорогая ... она используется для развязки, чтобы обеспечить хорошую архитектуру ... для по той же причине это не подходит для критических ситуаций с производительностью ... еще раз, отправка события стоит дорого ...
Я сделал небольшой урок, это немного больше руководства (это просто для моей точки зрения, хотя это может быть использовано в теории):
package {
import flash.utils.*;
public class Ticker {
//{ region private vars
private var _interval:int;
private var _tick:uint = 0;
private var _tickLength:Number;
private var _callBacks:Dictionary;
//} endregion
public function Ticker(tickLength:Number = 0) {
this.tickLength = tickLength;
this._callBacks = new Dictionary();
}
//{ region accessors
/**
* the current tick
*/
public function get tick():uint { return _tick; }
/**
* the tick length. set to a non-positive value, to stop ticking
*/
public function get tickLength():Number { return _tickLength; }
public function set tickLength(value:Number):void {
if (this._tickLength > 0) clearInterval(this._interval);
if ((this._tickLength = value) > 0) this._interval = setInterval(this.doTick, value);
}
//} endregion
/**
* add a callback, to be called with every tick
* @param callback function (tick:int):*
*/
public function addCallback(callback:Function):void {
this._callBacks[callback] = callback;
}
/**
* removes a callback previously added and returns true on success, false otherwise
* @param callback
* @return
*/
public function removeCallback(callback:Function):Boolean {
return delete this._callBacks[callback];
}
/**
* executes a tick. actually this happens automatically, but if you want to, you can set tickLength to a non-positive value and then execute ticks manually, if needed
*/
public function doTick():void {
var tick:uint = this._tick++;//actually, this is only superspicion ... amazingly, this makes no difference really ... :D
for each (var callback:* in this._callBacks) callback(tick);
}
}
}
он работает довольно хорошо ... здесь класс бенчмаркинга (вы можете просто использовать его как класс документа в FLA, если вы используете CS3 / CS4):
package {
//{ region imports
import flash.display.*;
import flash.events.*;
import flash.sampler.getSize;
import flash.system.System;
import flash.text.*;
import flash.utils.*;
//} endregion
public class Main extends MovieClip {
//{ region configuration
private const timers:Boolean = false;//true for Timer, false for Ticker
private const delay:Number = 500;
private const baseCount:uint = 10000;//base count of functions to be called
private const factor:Number = 20;//factor for Ticker, which is a little more performant
//} endregion
//{ region vars/consts
private const count:uint = baseCount * (timers ? 1 : factor);
private const nullMem:uint = System.totalMemory;//this is the footprint of the VM ... we'll subtract it ... ok, the textfield is not taken into account, but that should be alright ... i guess ...
private var monitor:TextField;
private var frameCount:uint = 0;
private var secCount:uint = 0;
//} endregion
public function Main():void {
var t:Ticker = new Ticker(delay);
var genHandler:Function = function ():Function {
return function (e:TimerEvent):void { };
}
var genCallback:Function = function ():Function {
return function (tick:uint):void { };
}
for (var i:uint = 0; i < count; i++) {
if (timers) {
var timer:Timer = new Timer(delay, 0);
timer.addEventListener(TimerEvent.TIMER, genHandler());
timer.start();
}
else {
t.addCallback(genCallback());
}
}
this.addChild(this.monitor = new TextField());
this.monitor.autoSize = TextFieldAutoSize.LEFT;
this.monitor.defaultTextFormat = new TextFormat("_typewriter");
this.addEventListener(Event.ENTER_FRAME, function (e:Event):void { frameCount++ });
setInterval(function ():void {
monitor.text = "Memory usage: "
+ groupDidgits(System.totalMemory - nullMem)
+ " B\navg. FPS: " + (frameCount /++secCount).toPrecision(3)
+ "\nuptime: " + secCount + "\nwith " + count + " functions";
}, 1000);
}
private function groupDidgits(n:int,sep:String = " "):String {
return n.toString().split("").reverse().map(function (c:String, i:int, ...rest):String { return c + ((i % 3 == 0 && i > 0) ? sep : ""); } ).reverse().join("");
}
}
}
на моей машине с таргетингом 60 FPS я получаю средний FPS 6,4 (через 3 минуты) и 10–14 МБ использования памяти (колебания происходят из-за того, что объекты TimerEvent необходимо собирать мусором) для 10000 функций вызывается с таймерами ... используя другой класс, я получаю 55.2 FPS с использованием 95.0 МБ памяти (очень постоянный, колебания составляют 1%) с непосредственным вызовом 200000 функций ... это означает, что при коэффициенте 20 вы получаете частоту кадров, которая в 9 раз выше, и вы используете только 8 раз памяти ... это должно дать вам представление о том, сколько места занимает таймер ...
это должно дать вам приблизительное представление о том, в каком направлении двигаться ...
[править] меня спросили, почему я использую частные переменные ... вопрос философии ... мое правило: никогда никому не позволять извне изменять состояние вашего объекта напрямую .. представьте, Ticker::_tickLength
был protected
... кто-то подклассов этого и пишет в эту переменную ... с каким эффектом? значение Ticker::tickLength
будет отличаться от длины интервала ... я не вижу преимущества ...
также, закрытые поля действительны только в классе ... что означает, что любой может переопределить их в подклассах без каких-либо коллизий ...
если я думаю, что у подклассов должен быть способ protected
воздействовать на состояние, определенное в суперклассе, я делаю установщик protected
... но, тем не менее, я могу реагировать ... я могу изменить / проверять / фиксировать значение, генерировать аргумент и ошибки диапазона по желанию, отправлять события и так далее ... если вы пишете класс, вы сами несете ответственность за поддержание целостности его состояния и влияния на его поведение ...
не раскрывайте внутреннюю работу вашего класса ... вам может понадобиться изменить их, нарушив зависимый код ... а также: подклассы сильно переоценены ... :)
вот почему ... [/ edit]
Greetz
back2dos