Electron 多线程池
多线程池
bash
一开始就会在内存中开辟空间,然后线程池会从内存中取出线程,然后执行任务,执行完任务之后,线程会归还到内存中,然后等待下一个任务。
线程最大数最小数
- Electron 默认最大线程数是 6,最小线程数是 3
使用
创建线程池
- 在 app.vue 中创建线程池
html
<template>
<router-view />
</template>
<script>
import { ipcApiRoute } from "@/api/main";
import { ipc } from "@/utils/ipcRenderer";
import { onMounted } from "vue";
export default {
name: "App",
setup() {
document.getElementById("loadingPage").remove();
onMounted(() => {
// 框架规定最多只能6个。最小3个 。这样不会造成用户设备卡死
console.log("没执行吗");
ipc.send(ipcApiRoute.createpool, 6);
ipc.on(ipcApiRoute.createPoolNotice, (event, result) => {
console.log("********");
console.log(result);
});
});
},
};
</script>
<style lang="less"></style>
- 控制器
js
async createpool(num, event) {
await Services.get("testjobpool").doCreatePool(num, event);
}
- Service 层
js
/**
* 创建pool
*/
doCreatePool(num, event) {
const channel = "controller.testjobpool.createPoolNotice";
this.myJobPool.create(num).then((pids) => {
event.reply(`${channel}`, "创建成功,进程号列表" + pids);
});
}
使用
- html
html
<button @click="openjobpool">开启多线程监听(有线程池)</button>
- js
js
// 监听
created() {
this.initxcpool();
},
// 函数
initxcpool() {
ipc.on(ipcApiRoute.testjobpoollistener, this.callbackxcpool);
},
// 回调
callbackxcpool(event, result) {
console.log("********");
console.log(result);
},
// 开启
openjobpool() {
let params = {
id: this.id,
action: "run",
};
ipc.send(ipcApiRoute.doJobPool, params);
},
// 关闭
closejobpool() {
let params = {
id: this.id,
action: "close",
};
ipc.send(ipcApiRoute.doJobPool, params);
},
- 控制器
js
async doJobpool(params, event) {
await Services.get("testjobpool").doJobByPool(
params.id,
params.action,
event
);
}
- Service 层
js
/**
* 通过进程池执行任务
*/
doJobByPool(jobId, action, event) {
let res = {};
const channel = "controller.testjob.testjobpoollistener";
// 异步-执行任务及监听进度 执行job里面的多线程就是路径
this.myJobPool
.runPromise("./jobs/testjobpool/testpools", { jobId, action })
.then((task) => {
// 监听器名称唯一,否则会出现重复监听。
// 任务完成时,需要移除监听器,防止内存泄漏
let eventName = "job-timer-progress-" + jobId;
task.emitter.on(eventName, (data) => {
Log.info(
"[main-process] [ChildPoolJob] timerTask, from TimerJob data:",
data
);
console.log(this.myJobPool.getPids());
// 发送数据到渲染进程
event.sender.send(`${channel}`, data);
// 如果收到任务完成的消息,移除监听器
if (data.end) {
task.emitter.removeAllListeners(eventName);
}
});
res.pid = task.pid;
});
return res;
}
- JOB 要执行的
js
/**
* @Author: jsopy
* @Date: 2024-09-12 11:46:17
* @LastEditTime: 2024-09-12 16:42:18
* @FilePath: /demo1/electron/jobs/testjobpool/testpools.js
* @Description:
* @
*/
const Job = require("ee-core/jobs/baseJobClass");
const Loader = require("ee-core/loader");
const Log = require("ee-core/log");
const Ps = require("ee-core/ps");
const { childMessage } = require("ee-core/message");
/**
* example - Testjobpool
* @class
*/
class Testjobpool extends Job {
constructor(params) {
super();
this.params = params;
}
/**
* handle()方法是必要的,且会被自动调用
*/
async handle() {
Log.info("[child-process] Testjobpool params: ", this.params);
let timer = null;
let jobId = this.params.jobId;
let eventName = "job-timer-progress-" + jobId;
if (this.params.action == "run") {
// 计时器任务
let number = 0;
timer = setInterval(function () {
// childMessage.send(eventName, { jobId, number, end: false });
childMessage.send(eventName, { jobId, number, end: false });
number++;
}, 1000);
// 用 setTimeout 模拟任务运行时长
setTimeout(() => {
// 关闭定时器
clearInterval(timer);
// 任务结束,重置前端显示
childMessage.send(eventName, { jobId, number: 0, pid: 0, end: true });
// 如果是childJob任务,必须调用 Ps.exit() 方法,让进程退出,否则会常驻内存
// 如果是childPoolJob任务,常驻内存,等待下一个业务
if (Ps.isChildJob()) {
Ps.exit();
}
}, 10 * 1000);
}
if (this.params.action == "close") {
clearInterval(timer);
// 任务结束,重置前端显示
childMessage.send(eventName, { jobId, number: 0, pid: 0, end: true });
}
}
}
Testjobpool.toString = () => "[class Testjobpool]";
module.exports = Testjobpool;
总结
流程
页面->控制器->服务层->JOB
注意
- eventName 服务层和 JOB 里面必须一致
- JOB 里面要使用 childMessage.send(eventName, { jobId, number, end: false }); 发送数据到主进程
- JOB 里面要使用 Ps.exit(); 退出进程
- JOB 里面要使用 Ps.isChildJob(); 判断是否是子进程
控制器代码如下
js
"use strict";
const { Controller } = require("ee-core");
const Services = require("ee-core/services");
/**
* example
* @class
*/
class TestjobPoolController extends Controller {
constructor(ctx) {
super(ctx);
}
/**
* 所有方法接收两个参数
* @param args 前端传的参数
* @param event - ipc通信时才有值。详情见:控制器文档
*/
/**
*
*/
async doJobpool(params, event) {
await Services.get("testjobpool").doJobByPool(
params.id,
params.action,
event
);
}
async createpool(num, event) {
await Services.get("testjobpool").doCreatePool(num, event);
}
}
TestjobPoolController.toString = () => "[class TestjobPoolController]";
module.exports = TestjobPoolController;
Service 层代码如下
js
const { ChildPoolJob } = require("ee-core/jobs");
const { Service } = require("ee-core");
const Log = require("ee-core/log");
/**
* 示例服务(service层为单例)
* @class
*/
class Testjobpool extends Service {
constructor(ctx) {
super(ctx);
// 在构造函数中初始化一些变量
this.myJobPool = new ChildPoolJob();
}
/**
* 创建pool
*/
doCreatePool(num, event) {
const channel = "controller.testjobpool.createPoolNotice";
this.myJobPool.create(num).then((pids) => {
event.reply(`${channel}`, "创建成功,进程号列表" + pids);
});
}
/**
* 通过进程池执行任务
*/
doJobByPool(jobId, action, event) {
let res = {};
const channel = "controller.testjob.testjobpoollistener";
// 异步-执行任务及监听进度
this.myJobPool
.runPromise("./jobs/testjobpool/testpools", { jobId, action })
.then((task) => {
// 监听器名称唯一,否则会出现重复监听。
// 任务完成时,需要移除监听器,防止内存泄漏
let eventName = "job-timer-progress-" + jobId;
task.emitter.on(eventName, (data) => {
Log.info(
"[main-process] [ChildPoolJob] timerTask, from TimerJob data:",
data
);
console.log(this.myJobPool.getPids());
// 发送数据到渲染进程
event.sender.send(`${channel}`, data);
// 如果收到任务完成的消息,移除监听器
if (data.end) {
task.emitter.removeAllListeners(eventName);
}
});
res.pid = task.pid;
});
return res;
}
}
Testjobpool.toString = () => "[class Testjobpool]";
module.exports = Testjobpool;
Job 代码如下
- 路径->jobs->testjobpool>testpools.js
js
/**
* @Author: jsopy
* @Date: 2024-09-12 11:46:17
* @LastEditTime: 2024-09-12 16:42:18
* @FilePath: /demo1/electron/jobs/testjobpool/testpools.js
* @Description:
* @
*/
const Job = require("ee-core/jobs/baseJobClass");
const Loader = require("ee-core/loader");
const Log = require("ee-core/log");
const Ps = require("ee-core/ps");
const { childMessage } = require("ee-core/message");
/**
* example - Testjobpool
* @class
*/
class Testjobpool extends Job {
constructor(params) {
super();
this.params = params;
}
/**
* handle()方法是必要的,且会被自动调用
*/
async handle() {
Log.info("[child-process] Testjobpool params: ", this.params);
let timer = null;
let jobId = this.params.jobId;
let eventName = "job-timer-progress-" + jobId;
if (this.params.action == "run") {
// 计时器任务
let number = 0;
timer = setInterval(function () {
// childMessage.send(eventName, { jobId, number, end: false });
childMessage.send(eventName, { jobId, number, end: false });
number++;
}, 1000);
// 用 setTimeout 模拟任务运行时长
setTimeout(() => {
// 关闭定时器
clearInterval(timer);
// 任务结束,重置前端显示
childMessage.send(eventName, { jobId, number: 0, pid: 0, end: true });
// 如果是childJob任务,必须调用 Ps.exit() 方法,让进程退出,否则会常驻内存
// 如果是childPoolJob任务,常驻内存,等待下一个业务
if (Ps.isChildJob()) {
Ps.exit();
}
}, 10 * 1000);
}
if (this.params.action == "close") {
clearInterval(timer);
// 任务结束,重置前端显示
childMessage.send(eventName, { jobId, number: 0, pid: 0, end: true });
}
}
}
Testjobpool.toString = () => "[class Testjobpool]";
module.exports = Testjobpool;
这里特别注意
特别注意
子进程里面使用不了ElectronApi,要是想使用,只有通过childMessage.send(eventName, { jobId, number, end: false });来发送消息,在主进程里面监听,然后通过event.sender.send(`${channel}`, data);来发送消息到渲染进程