AS3计时器与ENTER_FRAME性能 [英] AS3 Timers vs. ENTER_FRAME performance

查看:436
本文介绍了AS3计时器与ENTER_FRAME性能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要建一个游戏,有一些搬东西的时候,所以我用了很多计时器实例来控制重复和触发议案。

I'm building a game that got some moving things all the time, so I'm using a lot of Timer instances to control repetition and trigger motion.

现在的事情是,我开始注意到一些性能滞​​后。这是由于定时器?和你建议使用ENTER_FRAME事件呢?

Now the thing is that I started to notice some performance "lags". Is this due to the timers? and do you suggest using ENTER_FRAME event instead?

相关阅读:你建议任何其他库/方法,这样的游戏,可以提高性能?简单吐温库是不够的本身。

Related: Do you suggest any other library/method for such games that could enhance performance? Simple Tween libraries are not enough per se.

推荐答案

也许会更有意义,有只有一个定时运行对于这个问题... 据我所知,正在运行的计时器需要一个整体的线程... 把它放在伪code,定时器线程的主要code是类似的东西...

maybe it would make more sense, to have only one timer running for that matter ... as far as i know, a running Timer needs a whole thread ... to put it in pseudo-code, the Timer thread's main code is something like that ...

while (input.isEmpty()) {
    wait(interval);
    output.add({timerId:thisId, tickId: tickId++});
}

输出端是一个出队的主线程(执行ABC)检查每一个现在的话......有许多计时器,你将有很多线程,这是一个不必要的开销......此外,对于每一个事件,消息从计时器到主线程发送需要被弹出的双端队列,这是昂贵的,因为它必须是线程安全...然后相应的定时器已被发现,一个计时器事件必须创建​​(分配是也相当costy),然后出动,这也就是多次调用问题......

output being a dequeue the main thread (which executes the ABC) checks every now an then ... having many Timers, you will have many threads, which is an unnecessary overhead ... also, for every event, the message sent from the timer to the main thread needs to be popped of the deque, which is expensive, since it has to be thread safe ... and then the corresponding timer has to be found, a timer event has to be created (allocation is also quite costy) and then dispatched, which also is a matter of multiple calls ...

所以要尽量有一个计时器,或使用setInterval的...同时,考虑,在Flash事件模型是相当不错的,但价格昂贵......它用于去耦,以确保一个很好的架构......为由于同样的原因,这是不好的性能关键情况...再次,调度事件是昂贵...

so try to have ONE timer, or use setInterval ... also, consider, that the Event model in flash is quite nice, but expensive ... it is used for decoupling, to ensure a nice architecture ... for the same reason, it is not good for performance critical situations ... once again, dispatching an event is expensive ...

我做了一个小的类,这是一个小更手动(这只是我的观点,尽管它oculd在理论上可以使用):

i've made a little class, that is a little more manual (it's just to make my point, although it oculd be used in theory):

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):

it performs quite well ... here a benchmarking class (you should be able to simply use it as document class in a fla, if you use 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 targetet,我得到了6.4(3分钟后)和10-14 MB内存使用量的平均FPS(波动源于一个事实,即TimerEvent对象需要垃圾回收)为10000函数被调用定时器......使用另一个类,我得到55.2 FPS与95.0 MB内存使用率(非常稳定,波动温特1%)与200000的功能被直接调用......这意味着,在因子20,你得到一个帧率的要高9倍,而你只用8倍的内存... ...这应该给你多少足迹定时器产生......的想法

on my machine, with 60 FPS targetet, i get an average FPS of 6.4 (after 3 minutes) and 10-14 MB memory usage (fluctuation comes from the fact that TimerEvent objects need to be garbage collected) for 10000 functions being called with timers ... using the other class, i get 55.2 FPS with 95.0 MB memory usage (very constant, fluctuations are unter 1%) with 200000 functions being called directly ... this means, at factor 20 you get a framerate that is 9 times higher, and you use only 8 times the memory ... this should get you an idea of how much footprint a timer creates ...

这应该让你一个粗略的想法,往哪个方向走......

this should get you a rough idea, in which direction to go ...

我一直在问,为什么我用私人瓦尔...哲学的事...我的原则:永远让外界改变你的对象的状态直接的人。 ..想象新浪体育讯北京时间:: _ tickLength 保护 ...有人子类它,并写入该变量...有什么样的影响?对新浪体育讯北京时间:: tickLength 的价值将是区间长度不同的...我真的没有看到一个优势......

[edit] i've been asked, why i use private vars ... matter of philosophy ... my rule: never ever let anyone from outside change the state of your object directly ... imagine Ticker::_tickLength was protected ... someone subclasses it, and writes to that variable ... with what effect? the value of Ticker::tickLength will be different from the interval length ... i don't really see an advantage ...

另外,私有字段只在一类有效的...这意味着任何人都可以子类中重新定义它们没有任何碰撞......

also, private fields are only valid in a class ... which means anyone can redefine them within subclasses without any collisions ...

如果我想,子类应该有一个保护办法采取超类中定义的状态效果,我做一个保护二传......不过,我仍然可以作出反应......我可以改变/验证/夹值,抛出的参数和范围错误的意愿,调度事件,等等...如果你写一个类,你自己有责任维护其状态的完整性和其行为的影响......

if i think, that subclasses should have a protected way to take effect on the state defined in the superclass, i make a protected setter ... but still, i can react ... i can change/validate/clamp the value, throw argument and range errors at will, dispatch events, and so on ... if you write a class, you yourself are responsible for maintaining the integrity of its state and the effects on its behaviour ...

不要暴露你的类的内部工作......你可能需要改变他们,打破依赖code ...,也:子类是巨大的overrrated ... :)

do not expose the inner workings of your class ... you may need to change them, breaking dependant code ... and also: subclassing is hugely overrrated ... :)

所以这就是为什么... [/编辑]

so that's why ... [/edit]

这篇关于AS3计时器与ENTER_FRAME性能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆