PrimeNumbersWorld
Spark projectにマルチスレッド用ライブラリを公開したので、そのサンプルコードを移植してみました。
リアルタイムに素数を検索して画面に表示していきます。
Threader
http://www.libspark.org/wiki/Threader
/**
* Copyright shohei909 ( http://wonderfl.net/user/shohei909 )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/ipyi
*/
package{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.text.TextField;
import flash.utils.Timer;
import net.hires.debug.Stats;
//Threaderライブラリ
//import org.libspark.threader.Thread;
//import org.libspark.threader.Threader;
/**
* MIT Lisence
* @author shohei909
*/
[SWF(backgroundColor="0xFFFFFF",width="465",height="465",frameRate="30")]
public class PrimeNumbersWorld extends Sprite {
private const W:int = 465;
private const H:int = 465;
private var bitmapData:BitmapData = new BitmapData(W,H);
private var textField:TextField = new TextField();
function PrimeNumbersWorld() {
addChild(new Bitmap(bitmapData));
addChild(new Stats()).alpha = 0.7;
textField.x = 0;
textField.text = "2";
textField.textColor = 0x111111;
textField.autoSize = "left";
drawText( bitmapData, textField );
addEventListener( "enterFrame", onFrame );
//スレッド開始
Threader.addThread( threadMethod );
}
//素数の検索を行うメソッドです。
//forやwhileの変わりにt.loopを使うことでマルチスレッドを実現します。
private function threadMethod( t:Thread ):void {
var primes:Array = [2];
var i:uint = 3;
t.loop(
function _():Boolean{ //ループさせる処理を記述
var count:int = 0;
var prime:uint = primes[count];
var flag:Boolean = true;
t.loop(
function _():Boolean{ //ループさせる処理を記述
if( !(prime*prime <= i) ) return false; //ループ終了
if( i % prime == 0 ){ flag = false; return false; } //ループ終了
prime = primes[++count];
return true; //ループ続行
},
function _onComplete():void { //ループ終了後に呼び出される処理を記述
if (flag) {
primes.push( i ) ;
textField.text = i.toString();
drawText( bitmapData, textField );
}
i += 2;
});
return true; //無限ループ
});
}
private function drawText(bitmapData:BitmapData, textField:TextField):void {
var rate:int = Math.random()*Math.random()*Math.random()*20;
var mtr:Matrix = new Matrix(rate,0,0,rate,( Math.random()*bitmapData.width)-(textField.width*rate/2),( Math.random() *bitmapData.height)-(textField.height*rate/2));
bitmapData.draw(textField, mtr);
}
private var white:BitmapData = new BitmapData(W, H);
private function onFrame(e:Event):void {
bitmapData.unlock();
bitmapData.merge(white,bitmapData.rect, new Point, 30,30,30,0);
bitmapData.lock();
}
}
}
//Threaderを導入した場合以下は省略してください。
//Threaderライブラリ=================================================================================
import flash.utils.Timer;
import flash.utils.getTimer;
import flash.events.Event;
/**
* ThreadクラスはThreaderによって実行されるスレッドのクラスです。
*/
class Thread extends Object{
static private var threadNum:int = 0;
/** スレッドの優先度を指定します。推奨される値は0-1です。すべてのスレッドの優先度が1を超えていると、理論上は処理落ちが発生します。 */
public var rate:Number = Threader.defaultRate;
/** スレッドが正しく完了した時に呼び出される関数です。 */
public var onComplete:Function;
/** onCompleteに渡すパラメーターの配列です。 */
public var onCompleteParams:Array;
/** スレッドが破棄される時に呼び出される関数です。 */
public var onRemove:Function;
/** onRemoveに渡すパラメーターの配列です */
public var onRemoveParams:Array;
/** スレッドの制限時間(ミリ秒)です。スレッドの実行時間がtimeoutを超えると、スレッドは中断されます。timeoutを0に設定すると制限時間はありません。 */
public var timeout:uint = 0;
/** スレッドがタイムアウトする時に呼び出される関数です。 */
public var onTimeout:Function;
/** onTimeoutに渡すパラメーターの配列です。 */
public var onTimeoutParams:Array;
/** このスレッドの待機時間です。 */
public var delay:int = 0;
/** このスレッドの名前です。 */
public var name:String = "";
private var _span:Number = Threader.defaultRate;
/** このスレッドの呼び出し間隔です。 */
public function get span():Number { return _span; }
public function set span(s:Number):void { _span = s; _timer.delay = s; }
private var _currentLoop:Loop = null;
/** 現在進行中のループ処理です。 */
public function get currentLoop():Loop { return _currentLoop; }
private var _end:Boolean = false;
/** このスレッドが終了しているかどうかのBoolean値です。 */
public function get removed():Boolean { return _end; }
private var _loops:Vector.<Loop> = new Vector.<Loop>();
private var _limit:int = 5, _startTime:int = 0, _stopTime:int = 0, _waitTime:int = 0, _added:Boolean, currentLoops:Vector.<Loop>;
private var _timer:Timer;
/** このスレッドが現在進行中かどうかのBoolean値です。 */
public function get running():Boolean { return _timer.running; }
function Thread() {
_timer = new Timer(span);
_startTime = getTimer();
_timer.start();
threadNum++;
Threader.threads.push( this );
_timer.addEventListener( "timer", onFrame );
}
/**
* Threaderでは、loop関数で設定した関数を分割して実行することで、マルチスレッドが実現されます。
* このとき、注意すべき点はloopMethodの一度の実行に長時間かかってしまう場合、処理落ちを起こすということです。
*
* @param loopMethod 繰り返し呼び出す関数です。この関数はfalseをかえすまで繰り返し呼び出されます。
* @param onComplete ループが終了したときに呼び出される関数です。
* @param name このループの名前です。
*/
public function loop( loopMethod:Function, onComplete:Function = null, name:String = "" ):Loop{
var loop:Loop = new Loop( _currentLoop, loopMethod, onComplete,name );
if( _currentLoop == null ){ _loops.push( loop );
}else { _currentLoop.loops.push( loop ); _added = true; }
return loop;
}
/**
* このスレッドを破棄します。
*/
public function remove():void {
if( onRemove != null ){ onRemove() }
threadNum--;
Threader.threads.splice( Threader.threads.indexOf( this ), 1 );
_end = true;
_loops = null;
_currentLoop = null;
currentLoops = null;
_timer.stop();
_timer.removeEventListener( "timer", onFrame );
}
/**
* このスレッドを一時停止します。
*/
public function pause():void
{
if ( _timer.running ) {
_timer.stop();
_stopTime = getTimer();
if( delay <= 0 ){ threadNum--; }
}
}
/**
* このスレッドを再開します。
*/
public function resume():void
{
if ( !_timer.running ) {
_timer.start();
_startTime = getTimer();
if( delay <= 0 ){ threadNum++; }
}
}
/**
* 指定された時間(ミリ秒)だけスレッドを待機させます。
*/
public function sleep( delay:int ):void
{
if( delay > 0 ){
if ( running && delay > 0 ) { threadNum--; }
_waitTime = getTimer();
_limit = -1;
this.delay = delay;
}
}
private function onFrame(e:Event):void {
if ( timeout != 0 && timeout <= getTimer() - _startTime ) { if(onTimeout != null ){onTimeout.apply(null,onTimeoutParams)}; remove(); return; }
if ( delay > 0 ) {
delay += -getTimer() + _waitTime;
if ( delay <= 0 ) { delay = 0; threadNum++; }
_waitTime = getTimer();
_startTime += getTimer() - _waitTime;
}else {
var time:int = getTimer();
_limit = Math.ceil((span * rate) / threadNum - 1);
all: while(true){
if( _currentLoop == null ){
if ( _loops.length == 0 ) {
if( onComplete != null ){ onComplete.apply(null,onCompleteParams) }
remove();
return;
}
currentLoops = _loops;
_currentLoop = currentLoops[0];
}
do{
if ( _limit < getTimer() - time ) { break all; }
var cont:Boolean = _currentLoop.func.apply( null, _currentLoop.params );
}while ( cont && _added == false)
if( cont != true ){
currentLoops.reverse(); currentLoops.pop(); currentLoops.reverse();
}
if ( _added ) { _added = false; }
while( _currentLoop.loops.length == 0 ){
if( _currentLoop.onComplete != null ){ _currentLoop.onComplete() }
_currentLoop = _currentLoop.parent;
if( _currentLoop == null ) { continue all; }
}
currentLoops = _currentLoop.loops;
_currentLoop = currentLoops[0];
}
}
}
}
/**
* LoopクラスはThreaderによって実行されるループ処理のクラスです。
* @author shohei909
*/
class Loop extends Object{
public var func:Function;
public var params:Array;
public var onComplete:Function;
public var name:String;
public var parent:Loop;
public var loops:Vector.<Loop> = new Vector.<Loop>();
function Loop( parent:Loop, func:Function, onComplete:Function = null, name:String = "" ){
this.func = func; this.onComplete = onComplete; this.parent = parent; this.name = name;
}
}
/**
* Threaderクラスはスレッドを実行するための静的なクラスです。
* @author shohei909
*/
class Threader extends Object{
/** デフォルトの呼び出し間隔(ミリ秒)です。frameRateに合わせることで効率よく動作します。 */
static public var defaultSpan:Number = 1000/60;
/** デフォルトの優先度です。 */
static public var defaultRate:Number = 0.5;
/** 全てのスレッドへの参照です。 */
static public var threads:Vector.<Thread> = new Vector.<Thread>();
/**
* addThreadはThreaderの核となる関数です。
*
* Threaderでは、loop関数を含むFunctionをaddThread関数を使って実行することで、マルチスレッドが開始されます。
*
* @param threadMethod スレッドとして実行する関数です。funcの
* @param params threadMethodに渡すパラメーターの配列です。
* @param threadParameters スレッドに設定するパラメーターです。
* @return 追加されたスレッドです。
* @see Thread
* @see Thread#loop()
*/
static public function addThread( threadMethod:Function, threadParameters:Object = null, params:Array = null ):Thread {
var thread:Thread = new Thread();
for( var str:String in threadParameters ){
thread[str] = threadParameters[str];
}
if ( params == null ) {
thread.loop( threadMethod ).params = [thread]
}else{
thread.loop( threadMethod ).params = [thread].concat( params );
}
return thread;
}
/**
* 全てのスレッドを破棄します。
*/
static public function removeAllThreads():void {
for each( var t:Thread in threads ) { t.remove(); }
}
/**
* 現在進行中の全てのスレッドを一時停止します。
*/
static public function pauseAllThreads():void {
for each( var t:Thread in threads ) { t.pause(); }
}
/**
* 現在一時停止の全てのスレッドを再開します。
*/
static public function resumeAllThreads():void {
for each( var t:Thread in threads ) { t.resume(); }
}
/**
* 全てのスレッドを指定した時間(ミリ秒)だけ待機させます。
*/
static public function sleepAllThreads( delay:int ):void {
for each( var t:Thread in threads ) { t.sleep( delay ); }
}
/**
* nameが一致する、スレッドを破棄します。
*/
static public function removeThreads( name:String ):void {
for each( var t:Thread in threads ) { if(t.name==name)t.remove(); }
}
/**
* nameが一致する、現在進行中のスレッドを一時停止します。
*/
static public function pauseThreads( name:String ):void {
for each( var t:Thread in threads ) { if(t.name==name)t.pause(); }
}
/**
* nameが一致する、現在一時停止中のスレッドを再開します。
*/
static public function resumeThreads( name:String ):void {
for each( var t:Thread in threads ) { if(t.name==name)t.resume(); }
}
/**
* nameが一致する、スレッドを指定した時間(ミリ秒)だけ待機させます。
*/
static public function sleepThreads( name:String, delay:int ):void {
for each( var t:Thread in threads ) { if(t.name==name)t.sleep( delay ); }
}
}
//Threaderライブラリここまで==========================================================================================================