新增jobSystem
This commit is contained in:
49
source/bin/framework.d.ts
vendored
49
source/bin/framework.d.ts
vendored
@@ -1431,6 +1431,41 @@ declare module es {
|
|||||||
protected process(entities: Entity[]): void;
|
protected process(entities: Entity[]): void;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
declare module es {
|
||||||
|
/**
|
||||||
|
* JobSystem使用实体的子集调用Execute(entities),并在指定数量的线程上分配工作负载。
|
||||||
|
*/
|
||||||
|
abstract class JobSystem extends EntitySystem {
|
||||||
|
readonly _threads: number;
|
||||||
|
readonly _jobs: Job[];
|
||||||
|
readonly _executeStr: string;
|
||||||
|
constructor(matcher: Matcher, threads: number);
|
||||||
|
protected process(entities: Entity[]): void;
|
||||||
|
private queueOnThread;
|
||||||
|
/**
|
||||||
|
* 当操作完成时,改变的值需要用户进行手动传递
|
||||||
|
* 由于worker数据无法共享,所以这块需要特殊处理
|
||||||
|
* @example this.test = job[0].context.test;
|
||||||
|
* @param job
|
||||||
|
*/
|
||||||
|
protected abstract resetJob(job: Job): any;
|
||||||
|
/**
|
||||||
|
* 对指定实体进行多线程操作
|
||||||
|
* @param entity
|
||||||
|
*/
|
||||||
|
protected abstract execute(entity: Entity): any;
|
||||||
|
}
|
||||||
|
class Job {
|
||||||
|
entities: Entity[];
|
||||||
|
from: number;
|
||||||
|
to: number;
|
||||||
|
worker: Worker;
|
||||||
|
execute: string;
|
||||||
|
err: string;
|
||||||
|
context: any;
|
||||||
|
set(entities: Entity[], from: number, to: number, execute: string, context: any): void;
|
||||||
|
}
|
||||||
|
}
|
||||||
declare module es {
|
declare module es {
|
||||||
abstract class PassiveSystem extends EntitySystem {
|
abstract class PassiveSystem extends EntitySystem {
|
||||||
onChanged(entity: Entity): void;
|
onChanged(entity: Entity): void;
|
||||||
@@ -1998,19 +2033,9 @@ declare module es {
|
|||||||
/**
|
/**
|
||||||
* 创建一个worker
|
* 创建一个worker
|
||||||
* @param doFunc worker所能做的事情
|
* @param doFunc worker所能做的事情
|
||||||
*
|
|
||||||
* @example const worker = es.WorkerUtils.makeWorker(()=>{
|
|
||||||
* onmessage = ({data: {jobId, meesage}}) => {
|
|
||||||
* // worker内做的事
|
|
||||||
* console.log('我是线程', message, jobId);
|
|
||||||
* };
|
|
||||||
* });
|
|
||||||
*
|
|
||||||
* worker('主线程发送消息').then(message => {
|
|
||||||
* console.log('主线程收到消息', message);
|
|
||||||
* });
|
|
||||||
*/
|
*/
|
||||||
static makeWorker(doFunc: Function): (...message: any[]) => Promise<{}>;
|
static makeWorker(doFunc: Function): Worker;
|
||||||
|
static workerMessage(worker: Worker): (...message: any[]) => Promise<{}>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
declare module es {
|
declare module es {
|
||||||
|
|||||||
@@ -3174,6 +3174,90 @@ var es;
|
|||||||
es.IntervalIteratingSystem = IntervalIteratingSystem;
|
es.IntervalIteratingSystem = IntervalIteratingSystem;
|
||||||
})(es || (es = {}));
|
})(es || (es = {}));
|
||||||
var es;
|
var es;
|
||||||
|
(function (es) {
|
||||||
|
/**
|
||||||
|
* JobSystem使用实体的子集调用Execute(entities),并在指定数量的线程上分配工作负载。
|
||||||
|
*/
|
||||||
|
var JobSystem = /** @class */ (function (_super) {
|
||||||
|
__extends(JobSystem, _super);
|
||||||
|
function JobSystem(matcher, threads) {
|
||||||
|
var _this = _super.call(this, matcher) || this;
|
||||||
|
_this._threads = threads;
|
||||||
|
_this._jobs = new Array(threads);
|
||||||
|
for (var i = 0; i < _this._jobs.length; i++) {
|
||||||
|
_this._jobs[i] = new Job();
|
||||||
|
}
|
||||||
|
_this._executeStr = JSON.stringify(_this.execute, function (key, val) {
|
||||||
|
if (typeof val === 'function') {
|
||||||
|
return val + '';
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
});
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
JobSystem.prototype.process = function (entities) {
|
||||||
|
var _this = this;
|
||||||
|
var remainder = entities.length & this._threads;
|
||||||
|
var slice = entities.length / this._threads + (remainder == 0 ? 0 : 1);
|
||||||
|
var _loop_2 = function (t) {
|
||||||
|
var from = t * slice;
|
||||||
|
var to = from + slice;
|
||||||
|
if (to > entities.length) {
|
||||||
|
to = entities.length;
|
||||||
|
}
|
||||||
|
var job = this_1._jobs[t];
|
||||||
|
job.set(entities, from, to, this_1._executeStr, this_1);
|
||||||
|
if (from != to) {
|
||||||
|
var worker_1 = es.WorkerUtils.makeWorker(this_1.queueOnThread);
|
||||||
|
var workerDo = es.WorkerUtils.workerMessage(worker_1);
|
||||||
|
workerDo(job).then(function (message) {
|
||||||
|
var job = message;
|
||||||
|
_this.resetJob(job);
|
||||||
|
worker_1.terminate();
|
||||||
|
}).catch(function (err) {
|
||||||
|
job.err = err;
|
||||||
|
worker_1.terminate();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var this_1 = this;
|
||||||
|
for (var t = 0; t < this._threads; t++) {
|
||||||
|
_loop_2(t);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
JobSystem.prototype.queueOnThread = function () {
|
||||||
|
onmessage = function (_a) {
|
||||||
|
var _b = _a.data, jobId = _b.jobId, message = _b.message;
|
||||||
|
var job = message[0];
|
||||||
|
var executeFunc = JSON.parse(job.execute, function (k, v) {
|
||||||
|
if (v.indexOf && v.indexOf('function') > -1) {
|
||||||
|
return eval("(function(){return " + v + " })()");
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
});
|
||||||
|
for (var i = job.from; i < job.to; i++) {
|
||||||
|
executeFunc.call(job.context, job.entities[i]);
|
||||||
|
}
|
||||||
|
postMessage({ jobId: jobId, result: message }, null);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
return JobSystem;
|
||||||
|
}(es.EntitySystem));
|
||||||
|
es.JobSystem = JobSystem;
|
||||||
|
var Job = /** @class */ (function () {
|
||||||
|
function Job() {
|
||||||
|
}
|
||||||
|
Job.prototype.set = function (entities, from, to, execute, context) {
|
||||||
|
this.entities = entities;
|
||||||
|
this.from = from;
|
||||||
|
this.to = to;
|
||||||
|
this.execute = execute;
|
||||||
|
this.context = context;
|
||||||
|
};
|
||||||
|
return Job;
|
||||||
|
}());
|
||||||
|
})(es || (es = {}));
|
||||||
|
var es;
|
||||||
(function (es) {
|
(function (es) {
|
||||||
var PassiveSystem = /** @class */ (function (_super) {
|
var PassiveSystem = /** @class */ (function (_super) {
|
||||||
__extends(PassiveSystem, _super);
|
__extends(PassiveSystem, _super);
|
||||||
@@ -4089,7 +4173,8 @@ var es;
|
|||||||
};
|
};
|
||||||
EntityList.prototype.removeFromTagList = function (entity) {
|
EntityList.prototype.removeFromTagList = function (entity) {
|
||||||
var list = this._entityDict.get(entity.tag);
|
var list = this._entityDict.get(entity.tag);
|
||||||
list.delete(entity);
|
if (list)
|
||||||
|
list.delete(entity);
|
||||||
};
|
};
|
||||||
EntityList.prototype.update = function () {
|
EntityList.prototype.update = function () {
|
||||||
var e_11, _a;
|
var e_11, _a;
|
||||||
@@ -4960,21 +5045,13 @@ var es;
|
|||||||
/**
|
/**
|
||||||
* 创建一个worker
|
* 创建一个worker
|
||||||
* @param doFunc worker所能做的事情
|
* @param doFunc worker所能做的事情
|
||||||
*
|
|
||||||
* @example const worker = es.WorkerUtils.makeWorker(()=>{
|
|
||||||
* onmessage = ({data: {jobId, meesage}}) => {
|
|
||||||
* // worker内做的事
|
|
||||||
* console.log('我是线程', message, jobId);
|
|
||||||
* };
|
|
||||||
* });
|
|
||||||
*
|
|
||||||
* worker('主线程发送消息').then(message => {
|
|
||||||
* console.log('主线程收到消息', message);
|
|
||||||
* });
|
|
||||||
*/
|
*/
|
||||||
WorkerUtils.makeWorker = function (doFunc) {
|
WorkerUtils.makeWorker = function (doFunc) {
|
||||||
var _this = this;
|
|
||||||
var worker = new Worker(URL.createObjectURL(new Blob(["(" + doFunc.toString() + ")()"])));
|
var worker = new Worker(URL.createObjectURL(new Blob(["(" + doFunc.toString() + ")()"])));
|
||||||
|
return worker;
|
||||||
|
};
|
||||||
|
WorkerUtils.workerMessage = function (worker) {
|
||||||
|
var _this = this;
|
||||||
worker.onmessage = function (_a) {
|
worker.onmessage = function (_a) {
|
||||||
var _b = _a.data, result = _b.result, jobId = _b.jobId;
|
var _b = _a.data, result = _b.result, jobId = _b.jobId;
|
||||||
if (typeof _this.pendingJobs[jobId] == 'function')
|
if (typeof _this.pendingJobs[jobId] == 'function')
|
||||||
|
|||||||
2
source/bin/framework.min.js
vendored
2
source/bin/framework.min.js
vendored
File diff suppressed because one or more lines are too long
102
source/src/ECS/Systems/JobSystem.ts
Normal file
102
source/src/ECS/Systems/JobSystem.ts
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
module es {
|
||||||
|
/**
|
||||||
|
* JobSystem使用实体的子集调用Execute(entities),并在指定数量的线程上分配工作负载。
|
||||||
|
*/
|
||||||
|
export abstract class JobSystem extends EntitySystem {
|
||||||
|
public readonly _threads: number;
|
||||||
|
public readonly _jobs: Job[];
|
||||||
|
public readonly _executeStr: string;
|
||||||
|
|
||||||
|
constructor(matcher: Matcher, threads: number) {
|
||||||
|
super(matcher);
|
||||||
|
|
||||||
|
this._threads = threads;
|
||||||
|
this._jobs = new Array(threads);
|
||||||
|
for (let i = 0; i < this._jobs.length; i++) {
|
||||||
|
this._jobs[i] = new Job();
|
||||||
|
}
|
||||||
|
this._executeStr = JSON.stringify(this.execute, function (key, val) {
|
||||||
|
if (typeof val === 'function') {
|
||||||
|
return val + '';
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected process(entities: Entity[]) {
|
||||||
|
let remainder = entities.length & this._threads;
|
||||||
|
let slice = entities.length / this._threads + (remainder == 0 ? 0 : 1);
|
||||||
|
for (let t = 0; t < this._threads; t++) {
|
||||||
|
let from = t * slice;
|
||||||
|
let to = from + slice;
|
||||||
|
if (to > entities.length) {
|
||||||
|
to = entities.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
let job = this._jobs[t];
|
||||||
|
job.set(entities, from, to, this._executeStr, this);
|
||||||
|
if (from != to) {
|
||||||
|
const worker = WorkerUtils.makeWorker(this.queueOnThread);
|
||||||
|
const workerDo = WorkerUtils.workerMessage(worker);
|
||||||
|
workerDo(job).then((message) => {
|
||||||
|
let job = message as Job;
|
||||||
|
this.resetJob(job);
|
||||||
|
worker.terminate();
|
||||||
|
}).catch((err) => {
|
||||||
|
job.err = err;
|
||||||
|
worker.terminate();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private queueOnThread() {
|
||||||
|
onmessage = ({ data: { jobId, message } }) => {
|
||||||
|
let job = message[0] as Job;
|
||||||
|
let executeFunc: Function = JSON.parse(job.execute, function (k, v) {
|
||||||
|
if (v.indexOf && v.indexOf('function') > -1) {
|
||||||
|
return eval("(function(){return " + v + " })()")
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
});
|
||||||
|
for (let i = job.from; i < job.to; i++) {
|
||||||
|
executeFunc.call(job.context, job.entities[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
postMessage({ jobId, result: message }, null);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当操作完成时,改变的值需要用户进行手动传递
|
||||||
|
* 由于worker数据无法共享,所以这块需要特殊处理
|
||||||
|
* @example this.test = job[0].context.test;
|
||||||
|
* @param job
|
||||||
|
*/
|
||||||
|
protected abstract resetJob(job: Job);
|
||||||
|
/**
|
||||||
|
* 对指定实体进行多线程操作
|
||||||
|
* @param entity
|
||||||
|
*/
|
||||||
|
protected abstract execute(entity: Entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Job {
|
||||||
|
public entities: Entity[];
|
||||||
|
public from: number;
|
||||||
|
public to: number;
|
||||||
|
public worker: Worker;
|
||||||
|
public execute: string;
|
||||||
|
public err: string;
|
||||||
|
public context;
|
||||||
|
|
||||||
|
public set(entities: Entity[], from: number, to: number, execute: string, context: any) {
|
||||||
|
this.entities = entities;
|
||||||
|
this.from = from;
|
||||||
|
this.to = to;
|
||||||
|
this.execute = execute;
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -115,7 +115,8 @@ module es {
|
|||||||
|
|
||||||
public removeFromTagList(entity: Entity) {
|
public removeFromTagList(entity: Entity) {
|
||||||
let list = this._entityDict.get(entity.tag);
|
let list = this._entityDict.get(entity.tag);
|
||||||
list.delete(entity);
|
if (list)
|
||||||
|
list.delete(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public update() {
|
public update() {
|
||||||
|
|||||||
@@ -11,21 +11,14 @@ module es {
|
|||||||
/**
|
/**
|
||||||
* 创建一个worker
|
* 创建一个worker
|
||||||
* @param doFunc worker所能做的事情
|
* @param doFunc worker所能做的事情
|
||||||
*
|
|
||||||
* @example const worker = es.WorkerUtils.makeWorker(()=>{
|
|
||||||
* onmessage = ({data: {jobId, meesage}}) => {
|
|
||||||
* // worker内做的事
|
|
||||||
* console.log('我是线程', message, jobId);
|
|
||||||
* };
|
|
||||||
* });
|
|
||||||
*
|
|
||||||
* worker('主线程发送消息').then(message => {
|
|
||||||
* console.log('主线程收到消息', message);
|
|
||||||
* });
|
|
||||||
*/
|
*/
|
||||||
public static makeWorker(doFunc: Function) {
|
public static makeWorker(doFunc: Function) {
|
||||||
const worker = new Worker(URL.createObjectURL(new Blob([`(${doFunc.toString()})()`])));
|
const worker = new Worker(URL.createObjectURL(new Blob([`(${doFunc.toString()})()`])));
|
||||||
|
|
||||||
|
return worker;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static workerMessage(worker: Worker) {
|
||||||
worker.onmessage = ({ data: { result, jobId } }) => {
|
worker.onmessage = ({ data: { result, jobId } }) => {
|
||||||
if (typeof this.pendingJobs[jobId] == 'function')
|
if (typeof this.pendingJobs[jobId] == 'function')
|
||||||
this.pendingJobs[jobId](result);
|
this.pendingJobs[jobId](result);
|
||||||
|
|||||||
Reference in New Issue
Block a user