六狼论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博账号登陆

只需一步,快速开始

搜索
查看: 54|回复: 0

Introducing TurboSignals

[复制链接]

升级  50.4%

234

主题

234

主题

234

主题

进士

Rank: 4

积分
752
 楼主| 发表于 2013-1-15 02:18:05 | 显示全部楼层 |阅读模式
http://jacksondunstan.com/articles/585

My last article on Callback Strategies highlighted some pretty severe performance differences between my Runnable strategy, as3signals by Robert Penner, and Flash’s native Event system. My simple Runnable technique had an artificial advantage though: it was not a proper library but instead a little bit of code built right into the test app. Today I’m introducing TurboSignals as an AS3 library making use of the Runnable technique.


BASICS
TurboSignals is a simple library. It includes signal classes for up to ten parameters (tt>Signal0, Signal1, ..., Signal10) as well as a class for var args (SignalN). These are paired with slot interfaces (Slot0, Slot1, ..., Slot10 and SlotN) that you implement in order to receive the signal's callback. The purpose of an explicit slot type is to avoid using a Function variable, which is very slow. This was shown in my article on Runnables along with how Runnables are a good strategy for avoiding that slowdown. Some helper classes (FunctionSlot0, FunctionSlot1, ..., FunctionSlot10 and FunctionSlotN), however slow, are provided for when you really want to provide an arbitrary function.

ADVANCED FEATURES
One nicety of TurboSignals is that the dispatch operation is "safe" insomuch as that calls to addSlot, removeSlot, and removeAllSlots will not affect which slots are called. One drawback though is that parameters to dispatch are all untyped (*) and therefore there is no compile-time checking of the parameters and the possibility exists that there will be type errors at runtime. This is true too in the Event/EventDispatcher system as well as as3signals, only the latter explicitly checks for this problem at runtime to give more informative errors.

USAGE EXAMPLE (FASTER)
This example runs at maximum speed, which is probably not needed for simple button clicks.

import com.jacksondunstan.signals.*;
public class Button extends Sprite
{
    public var clicked:Signal0;
    public function Button()
    {
        addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
    }
    private function onMouseDown(ev:MouseEvent): void
    {
        this.clicked.dispatch();
    }
}
public class MainMenu implements Slot0
{
    public function MainMenu(button:Button)
    {
        button.clicked.addSlot(this);
    }
    public function onSignal0(): void
    {
        trace("button was clicked");
    }
}
USAGE EXAMPLE (SLOWER)
This example allows you to make your callback private and name it as you wish, courtesy of the FunctionSlot0 adapter class.

import com.jacksondunstan.signals.*;
public class Button extends Sprite
{
    public var clicked:Signal0;
    public function Button()
    {
        addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
    }
    private function onMouseDown(ev:MouseEvent): void
    {
        this.clicked.dispatch();
    }
}
public class MainMenu
{
    public function MainMenu(button:Button)
    {
        button.clicked.addSlot(new FunctionSlot0(onButtonClicked));
    }
    private function onButtonClicked(): void
    {
        trace("button was clicked");
    }
}
USAGE EXAMPLE (COMPLEX)
This example runs at maximum speed with multiple buttons.

import com.jacksondunstan.signals.*;
public class Button extends Sprite
{
    public var clicked:Signal1;
    public function Button()
    {
        addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
    }
    private function onMouseDown(ev:MouseEvent): void
    {
        this.clicked.dispatch(this);
    }
}
public class MainMenu implements Slot1
{
    private var __button1:Button;
    private var __button2:Button;
    public function MainMenu(button1:Button, button2:Button)
    {
        __button1 = button1;
        __button2 = button2;
        button1.clicked.addSlot(this);
        button2.clicked.addSlot(this);
    }
    public function onSignal1(target:Button): void
    {
        if (target == __button1)
        {
            trace("button 1 was clicked");
        }
        else if (target == __button2)
        {
            trace("button 2 was clicked");
        }
    }
}
PARAMETER PASSING STRATEGY
As you can see from above, functionality from alternative systems can be emulated in TurboSignals by simply adding more event parameters. The Event/EventDispatcher system's Event.target is attained by simply passing a reference to this as a parameter to dispatch. Likewise, the type field can easily be passed. You may also choose to pass objects like Event that include these too, which may help with speed as multiple arguments slow down the dispatch operation.

PERFORMANCE DATA
The TurboSignals distribution includes a suite of performance tests for TurboSignals as well as as3signals and Event/EventDispatcher. Here are the results for the first version:

TurboSignals - 1 Listener (1000000 dispatches)

ENVIRONMENT012345678910N
2.2 Ghz Intel Core 2 Duo, 2GB, Mac OS X 10.65691989710190941071041161191917
TurboSignals - 10 Listeners (1000000 dispatches)

ENVIRONMENT012345678910N
2.2 Ghz Intel Core 2 Duo, 2GB, Mac OS X 10.63176005705855676065825625806146287679
TurboSignals - 1 Function Listener (1000000 dispatches)

ENVIRONMENT012345678910N
2.2 Ghz Intel Core 2 Duo, 2GB, Mac OS X 10.63176005705855676065825625806146287679
TurboSignals - 10 Function Listeners (1000000 dispatches)

ENVIRONMENT012345678910N
2.2 Ghz Intel Core 2 Duo, 2GB, Mac OS X 10.62985335934493433355135643534359736243731386222184
as3signals - 1 Function Listener (1000000 dispatches)

ENVIRONMENT012345678910N
2.2 Ghz Intel Core 2 Duo, 2GB, Mac OS X 10.69541158132614181534169618181951205524672740n/a
as3signals - 10 Function Listeners (1000000 dispatches)

ENVIRONMENT012345678910N
2.2 Ghz Intel Core 2 Duo, 2GB, Mac OS X 10.625682908339436563918424945354805535462886912n/a
Event/EventDispatcher - 1 Function Listener (1000000 dispatches)

ENVIRONMENT012345678910N
2.2 Ghz Intel Core 2 Duo, 2GB, Mac OS X 10.6n/a4886n/an/an/an/an/an/an/an/an/an/a
Event/EventDispatcher - 10 Function Listeners (1000000 dispatches)

ENVIRONMENT012345678910N
2.2 Ghz Intel Core 2 Duo, 2GB, Mac OS X 10.6n/a33755n/an/an/an/an/an/an/an/an/an/a
PERFORMANCE GRAPHS
















PERFORMANCE ANALYSIS
The latest version of as3signals (as of today, 2/15/2010) goes a long way to improve performance of the Event/EventDispatcher system, especially on Mac OS X. TurboSignals goes a lot further though and nearly matches the speed of its inspiration: the simple list of Runnables. TurboSignals manages to dispatch events about 17 times faster than as3signals when implementing the slot directly and about 3 times faster than as3signals when using a Function variable to allow for a the callback to be private, named, or anonymous. That said, as3signals is itself 4-13x faster than the Event/EventDispatcher system. So if you are planning on dispatching frequently or to many listeners, you should definitely take a look at TurboSignals.

Tags: as3signals, events, runnables, turbosignals
您需要登录后才可以回帖 登录 | 立即注册 新浪微博账号登陆

本版积分规则

快速回复 返回顶部 返回列表