做業車間調度(Job shop scheduling problem, JSP) 是車間調度中最多見的調度類型,是最難的組合優化問題之一,應用領域極其普遍,涉及航母調度,機場飛機調度,港口碼頭貨船調度,汽車加工流水線等,所以對其研究具備重大的現實意義。科學有效的生產調度不但能夠提升生產加工過程當中工人、設備資源的高效利用,還可縮短生產週期,下降生產成本。
前端
一個加工系統有M臺機器,要求加工N個做業,其中,做業i包含工序數爲。令,則L爲任務集的總工序數。其中,各工序的加工時間已肯定,而且每一個做業必須按照工序的前後順序加工。調度的任務是安排全部做業的加工調度排序,約束條件被知足的同時,使性能指標獲得優化。做業車間調度須要考慮以下約束:java
問題的數學模型:
node
令(i,j)表示做業i的第j個工序。和分別表示(i,j)的加工起始時刻和加工時間。表示(i,j)是否在第k臺機器上加工:若是(i,j)在第k臺機器上加工,;不然,,爲第k臺機器的完工時間,則問題的數學模型以下:python
隨着遺傳算法(genetic algorithm (GA))在組合優化問題的普遍應用,許多人開始對遺傳算法進行深度研究。已有研究結果代表,遺傳算法對求解做業車間調度問題具備較好的效果,所以系統採用遺傳算法來解該問題,遺傳算法是計算數學中用於解決最優化的搜索算法,是進化算法的一種。進化算法最初是借鑑了進化生物學中的一些現象而發展起來的,這些現象包括遺傳、突變、天然選擇以及雜交等。系統經過模擬生物進化,包括遺傳、突變、選擇等,來不斷地產生新個體,並在算法終止時求得最優個體,即最優解。mysql
遺傳算法解決做業車間調度問題基本步驟git
流程圖以下
github
遺傳算法所需參數redis
遺傳算法實現基本步驟及僞代碼
算法
1. 編碼及初始化種羣
sql
採用工序實數編碼來表示染色體,即M臺機器,N個工件,每一個工件的工序數爲,則染色體長度爲,對染色體編碼以下:。其中表明第i個工件編號,而出現的次數表明該工件的第幾道工序。例如{0, 1, 2, 1, 2, 0, 0, 1, 2},中0,1,2表示工件的編號,第幾回出現就表明第幾道工序。而後將每一次隨機生成的染色體個體加入到種羣集合中。
2. 解碼及計算適應度
將優化目標定義爲總加工時間最短,所以適應度定義爲最短加工時間的倒數,設fitness爲對應個體的適應度,fulfillTime爲最短加工時間,所以 其中fulfillTime的計算方法以下:
首先定義以下變量
而後從左到右遍歷個體的染色體序列,其中表示第i個工件的編號,則對應的當前工序爲,設爲p。當前工件當前工序所使用的機器編號爲,設爲m。當前工件當前工序對應的加工時間爲,設爲t。則工件的第p道工序的最晚開始時間爲
而第m臺機器的加工時間爲
工件的第p道工序的結束時間爲最後加工完全部工件的最短加工時間fulfillTime爲
從而計算出適應度fitness。
3. 個體選擇算子
個體的選擇使用錦標賽法,其基本策略爲從整個種羣中隨機抽取n個個體讓它們競爭,選取其中最優的個體。該算子的選擇過程以下
4. 染色體交叉算子
使用Order Crossover(OX)交叉算子,該算子的交叉步驟以下:
對於一對染色體g1, g2,首先隨機產生一個起始位置start和終止位置end,並由從g1的染色體序列從start到end的序列中產生一個子代原型
將g2中不包含在child prototype的其他編碼加入到child prototype兩側
上述步驟將產生一個child,交換g1, g2便可產生另外一個child
5. 染色體變異算子
變異的做用主要是使算法能跳出局部最優解,所以不一樣的變異方式對算法可否求得全局最優解有很大的影響。使用位置變異法做爲變異算子,即從染色體中隨機產生兩個位置並交換這兩個位置的值
遺傳算法代碼實現
根據上面的步驟及僞代碼,很容易就能寫出Python及Java對應的代碼實現了(C++實如今這裏:遺傳算法與做業車間調度C++實現),以下:
Python代碼:
from random import (randint)
from typing import (List, Tuple, Set, Dict, Any)
from utils.utils import reshape_data
from collections import namedtuple
MATRIX_SIZE = 500
# 個體對象,染色體和適應度
class Gene(object):
def __init__(self, fitness: float = 0, chromosome = None):
self.fitness = fitness
self.chromosome: list = chromosome
def __eq__(self, other):
if isinstance(other, Gene):
return other.fitness == self.fitness and other.chromosome == self.chromosome
return False
def __hash__(self):
return hash("".join(map(lambda x: str(x), self.chromosome)))
def __str__(self):
return "{} => {}".format(self.chromosome, self.fitness)
# 存儲解碼結果
class GeneEvaluation:
def __init__(self):
self.fulfill_time = 0
self.machine_work_time = [0 for _ in range(MATRIX_SIZE)]
self.process_ids = [0 for _ in range(MATRIX_SIZE)]
self.end_time = [[0 for _ in range(MATRIX_SIZE)] for _ in range(MATRIX_SIZE)]
self.start_time = [[0 for _ in range(MATRIX_SIZE)] for _ in range(MATRIX_SIZE)]
# 遺傳算法實現
class GA:
def __init__(self, population_number = 50, times = 10, cross_probability = 0.95, mutation_probability = 0.05, workpiece_number = 0, machine_number = 0):
self.population_number = population_number # 種羣數量
self.times = times # 遺傳代數
self.cross_probability = cross_probability # 交叉機率
self.mutation_probability = mutation_probability # 突變機率
self.workpiece_number = workpiece_number # 工件數量
self.machine_number = machine_number # 機器數量
self.process_number: int = 0 # 工序數量
self.chromosome_size: int = 0 # 染色體長度
self.machine_matrix = [[-1 for _ in range(MATRIX_SIZE)] for _ in range(MATRIX_SIZE)]
self.time_matrix = [[-1 for _ in range(MATRIX_SIZE)] for _ in range(MATRIX_SIZE)]
self.process_matrix = [[-1 for _ in range(MATRIX_SIZE)] for _ in range(MATRIX_SIZE)]
self.genes: Set[Gene] = set()
# 評估染色體
def evaluate_gene(self, g: Gene) -> GeneEvaluation:
evaluation = GeneEvaluation()
# print(g.chromosome)
for workpiece_id in g.chromosome:
process_id = evaluation.process_ids[workpiece_id]
machine_id = self.machine_matrix[workpiece_id][process_id]
time = self.time_matrix[workpiece_id][process_id]
evaluation.process_ids[workpiece_id] += 1
evaluation.start_time[workpiece_id][process_id] = evaluation.machine_work_time[machine_id] \
if process_id == 0 else max(evaluation.end_time[workpiece_id][process_id - 1],
evaluation.machine_work_time[machine_id])
evaluation.machine_work_time[machine_id] = evaluation.start_time[workpiece_id][process_id] + time
evaluation.end_time[workpiece_id][process_id] = evaluation.machine_work_time[machine_id]
evaluation.fulfill_time = max(evaluation.fulfill_time, evaluation.machine_work_time[machine_id])
return evaluation
# 計算適應度
def calculate_fitness(self, g: Gene) -> float:
return 1 / self.evaluate_gene(g).fulfill_time
# 個體交叉
def gene_cross(self, g1: Gene, g2: Gene) -> tuple:
chromosome_size = self.chromosome_size
def gene_generate(father: Gene, mother: Gene) -> Gene:
index_list = list(range(chromosome_size))
p1 = index_list.pop(randint(0, len(index_list) - 1))
p2 = index_list.pop(randint(0, len(index_list) - 1))
start = min(p1, p2)
end = max(p1, p2)
prototype = father.chromosome[start: end + 1]
t = mother.chromosome[0:]
for v1 in prototype:
for i in range(len(t)):
if v1 == t[i]:
t.pop(i)
break
child = Gene()
child.chromosome = t[0: start] + prototype + t[start:]
child.fitness = self.calculate_fitness(child)
return child
return gene_generate(g1, g2), gene_generate(g2, g1)
# 突變
def gene_mutation(self, g: Gene, n = 2) -> None:
index_list = [i for i in range(self.chromosome_size)]
for i in range(n):
a = index_list.pop(randint(0, len(index_list) - 1))
b = index_list.pop(randint(0, len(index_list) - 1))
g.chromosome[a], g.chromosome[b] = g.chromosome[b], g.chromosome[a]
g.fitness = self.calculate_fitness(g)
# 初始化種羣 [0, 1, 2, 1, 2, 0, 0, 1] => 12
def init_population(self):
for _ in range(self.population_number):
g = Gene()
size = self.workpiece_number * self.machine_number
# print(self.workpiece_number, self.machine_number)
index_list = list(range(size))
chromosome = [-1 for _ in range(size)]
for j in range(self.workpiece_number):
for k in range(self.machine_number):
index = randint(0, len(index_list) - 1)
val = index_list.pop(index)
if self.process_matrix[j][k] != -1:
chromosome[val] = j
g.chromosome = list(filter(lambda x: x != -1, chromosome))
# print("chromosome:", g.chromosome)
g.fitness = self.calculate_fitness(g)
self.genes.add(g)
# 選擇個體,錦標賽法
def select_gene(self, n: int = 3):
if len(self.genes) <= 3:
best_gene = Gene(0)
for g in self.genes:
if g.fitness > best_gene.fitness:
best_gene = g
return best_gene
index_list = list(range(len(self.genes)))
index_set = {index_list.pop(randint(0, len(index_list) - 1)) for _ in range(n)}
best_gene = Gene(0)
i = 0
for gene in self.genes:
if i in index_set:
if best_gene.fitness < gene.fitness:
best_gene = gene
i += 1
return best_gene
# 遺傳算法
def exec(self, parameter: List[List[Tuple]]) -> GeneEvaluation:
# print(parameter)
workpiece_size = len(parameter)
for i in range(workpiece_size):
self.chromosome_size += len(parameter[i])
self.process_number = max(self.process_number, len(parameter[i]))
for j in range(len(parameter[i])):
self.machine_matrix[i][j] = parameter[i][j][0]
self.time_matrix[i][j] = parameter[i][j][1]
for i in range(workpiece_size):
for j in range(self.process_number):
if self.machine_matrix[i][j] != -1:
self.process_matrix[i][self.machine_matrix[i][j]] = j
self.init_population()
for _ in range(self.times):
probability = randint(1, 100) / 100
if probability < self.mutation_probability:
index = randint(0, len(self.genes))
i = 0
for gene in self.genes:
if i == index:
self.gene_mutation(gene)
break
i += 1
else:
g1, g2 = self.select_gene(), self.select_gene()
children = self.gene_cross(g1, g2)
self.genes.update({*children})
best_gene = Gene(0)
for gene in self.genes:
if best_gene.fitness < gene.fitness:
best_gene = gene
return self.evaluate_gene(best_gene)
ResultData = namedtuple("ResultData", ["fulfill_time", "row_data", "json_data"])
# 輸出結果
def schedule(data) -> ResultData:
print(data)
reshape = reshape_data(data)
parameter = reshape.result
print(parameter)
n = len(reshape.workpiece)
m = len(reshape.machine) # number from 0
print(m)
ga = GA(workpiece_number = n, machine_number = m)
result = ga.exec(parameter)
p = ga.process_number
machine_matrix = ga.machine_matrix
row_data = []
for i in range(n):
for j in range(p):
if machine_matrix[i][j] != -1:
temp = {
"workpiece": reshape.workpiece[i],
"process": reshape.process[i][j],
"machine": reshape.machine[machine_matrix[i][j]],
"startTime": result.start_time[i][j],
"endTime": result.end_time[i][j]
}
# print(i, j, machine_matrix[i][j], result.start_time[i][j], result.end_time[i][j])
row_data.append(temp)
json_data = {}
for i in range(n):
for j in range(p):
if machine_matrix[i][j] != -1:
temp = {
"workpiece": reshape.workpiece[i],
"process": reshape.process[i][j],
"startTime": result.start_time[i][j],
"endTime": result.end_time[i][j]
}
m = reshape.machine[machine_matrix[i][j]]
if m not in json_data:
json_data[m] = [temp]
else:
json_data[m].append(temp)
return ResultData(result.fulfill_time, row_data, json_data)
if __name__ == "__main__":
# 測試數據
d = [{'workpiece': '#W-89-10', 'process': '#P-1349-31', 'machine': '#M-8763-12', 'time': 10, 'order': 0},
{'workpiece': '#W-89-10', 'process': '#P-6261-32', 'machine': '#M-2304-14', 'time': 21, 'order': 1},
{'workpiece': '#W-89-10', 'process': '#P-6917-33', 'machine': '#M-6360-16', 'time': 12, 'order': 2},
{'workpiece': '#W-5863-13', 'process': '#P-2772-34', 'machine': '#M-6557-17', 'time': 21, 'order': 0},
{'workpiece': '#W-5863-13', 'process': '#P-468-35', 'machine': '#M-8763-12', 'time': 21, 'order': 1},
{'workpiece': '#W-5829-8', 'process': '#P-3959-28', 'machine': '#M-2304-14', 'time': 5, 'order': 2},
{'workpiece': '#W-5829-8', 'process': '#P-5852-27', 'machine': '#M-671-13', 'time': 11, 'order': 1},
{'workpiece': '#W-5829-8', 'process': '#P-7792-26', 'machine': '#M-8763-12', 'time': 10, 'order': 0},
{'workpiece': '#W-554-9', 'process': '#P-6810-29', 'machine': '#M-671-13', 'time': 5, 'order': 0}]
print(schedule(d).row_data)
複製代碼
工具reshape_data函數實現
from typing import (List, Dict)
from collections import namedtuple
test_data = [{"workpiece": '#W-5829-8',
"process": '#P-3959-28',
"machine": '#M-2304-14',
"time": 5,
"order": 2},
{"workpiece": '#W-5829-8',
"process": '#P-5852-27',
"machine": '#M-671-13',
"time": 11,
"order": 1},
{"workpiece": '#W-5829-8',
"process": '#P-7792-26',
"machine": '#M-8763-12',
"time": 10,
"order": 0},
{"workpiece": '#W-554-9',
"process": '#P-6810-29',
"machine": '#M-671-13',
"time": 5,
"order": 0},
{"workpiece": '#W-554-9',
"process": '#P-8883-30',
"machine": '#M-3836-15',
"time": 10,
"order": 1}]
ReshapeData = namedtuple("ReshapeData",
["result", "workpiece", "machine", "process", "reverse_workpiece", "reverse_machine"])
def make_reverse_index(arr: list) -> dict:
result = {}
for i in range(len(arr)):
result[arr[i]] = i
return result
def filter_value(origin: list, except_value: int) -> list:
return list(filter(lambda v: v != except_value, origin))
def reshape_data(data: List[Dict]) -> ReshapeData:
def make_array(r: dict) -> ReshapeData:
workpieces = list(set(map(lambda v: v["workpiece"], data)))
machines = list(set(map(lambda v: v["machine"], data)))
process = [-1 for _ in workpieces]
reverse_workpieces = make_reverse_index(workpieces)
reverse_machines = make_reverse_index(machines)
ans = [-1 for _ in r.keys()]
for key, val in r.items():
# print(val, type(val))
m = max(*map(lambda v: v["order"], val)) + 1 if len(val) > 1 else val[0]["order"]
t = [-1 for _ in range(m + 1)]
x = [-1 for _ in range(m + 1)]
for p in val:
t[p["order"]] = (reverse_machines[p["machine"]], p["time"])
x[p["order"]] = p["process"]
x = filter_value(x, -1)
t = filter_value(t, -1)
if ans[reverse_workpieces[key]] == -1:
ans[reverse_workpieces[key]] = t
else:
ans[reverse_workpieces[key]].append(t)
process[reverse_workpieces[key]] = x
process = filter_value(process, -1)
ans = filter_value(ans, -1)
return ReshapeData(ans, workpieces, machines, process, reverse_machines, reverse_workpieces)
result = {}
for value in data:
w = value["workpiece"]
if w in result:
result[w].append(value)
else:
result[w] = [value]
# print(result)
return make_array(result)
if __name__ == "__main__":
print(reshape_data(test_data).result)
print(reshape_data(test_data).machine)
複製代碼
同理Java也很容易實現:
import java.util.*;
class GeneticAlgorithm {
private final int populationNumber = 60;
private final double crossProbability = 0.95;
private final double mutationProbability = 0.05;
private int jobNumber;
private int machineNumber;
private int processNumber;
private int chromosomeSize;
private int[][] machineMatrix = new int[1024][1024];
private int[][] timeMatrix = new int[1024][1024];
private int[][] processMatrix = new int[1024][1024];
private Set<Gene> geneSet = new HashSet<>();
private Random random = new Random();
public GeneticAlgorithm(int jobNumber, int machineNumber) {
this.jobNumber = jobNumber;
this.machineNumber = machineNumber;
for (int[] matrix : this.machineMatrix) Arrays.fill(matrix, -1);
for (int[] process : this.processMatrix) Arrays.fill(process, -1);
}
private List<Integer> makeList(int n) {
List<Integer> result = new ArrayList<>();
for (int i = 0; i < n; i++) result.add(i);
return result;
}
private Integer[] filterArray(Integer[] arr, int filterVal) {
List<Integer> result = new ArrayList<>();
for (int i = 0; i < arr.length; i++) {
if (arr[i] != filterVal) {
result.add(arr[i]);
}
}
return result.toArray(new Integer[0]);
}
// 初始化種羣
public void initialPopulation() {
for (int i = 0; i < populationNumber; i ++) {
Gene g = new Gene();
int size = jobNumber * machineNumber;
List<Integer> indexList = makeList(size);
Integer[] chromosome = new Integer[size];
Arrays.fill(chromosome, -1);
for (int j = 0; j < jobNumber; j++) {
for (int k = 0; k < machineNumber; k ++) {
int index = random.nextInt(indexList.size());
int val = indexList.remove(index);
if (processMatrix[j][k] != -1) {
chromosome[val] = j;
}
}
}
g.chromosome = filterArray(chromosome, -1);
g.fitness = calculateFitness(g).fulfillTime;
geneSet.add(g);
}
}
public List<Integer> subArray(Integer[] arr, int start, int end) {
List<Integer> list = new ArrayList<>();
for (int i = start; i < end; i++) list.add(arr[i]);
return list;
}
// 計算適應度
public Result calculateFitness(Gene g) {
Result result = new Result();
for (int i = 0; i < g.chromosome.length; i ++) {
int jobId = g.chromosome[i];
int processId = result.processIds[jobId];
int machineId = machineMatrix[jobId][processId];
int time = timeMatrix[jobId][processId];
result.processIds[jobId] += 1;
result.startTime[jobId][processId] = processId ==0 ? result.machineWorkTime[machineId] :
Math.max(result.endTime[jobId][processId - 1], result.machineWorkTime[machineId]);
result.machineWorkTime[machineId] = result.startTime[jobId][processId] + time;
result.endTime[jobId][processId] = result.machineWorkTime[machineId];
result.fulfillTime = Math.max(result.fulfillTime, result.machineWorkTime[machineId]);
}
return result;
}
// 交叉算子
private Gene crossGene(Gene g1, Gene g2) {
List<Integer> indexList = makeList(chromosomeSize);
int p1 = indexList.remove(random.nextInt(indexList.size()));
int p2 = indexList.remove(random.nextInt(indexList.size()));
int start = Math.min(p1, p2);
int end = Math.max(p1, p2);
List<Integer> proto = subArray(g1.chromosome, start, end + 1);
List<Integer> t = new ArrayList<>();
for (Integer c : g2.chromosome) t.add(c);
for (Integer val : proto) {
for (int i = 0; i < t.size(); i++) {
if (val.equals(t.get(i))) {
t.remove(i);
break;
}
}
}
Gene child = new Gene();
proto.addAll(t.subList(start, t.size()));
List<Integer> temp = t.subList(0, start);
temp.addAll(proto);
child.chromosome = temp.toArray(new Integer[0]);
child.fitness = (double) calculateFitness(child).fulfillTime;
return child;
}
// 突變算子
public Gene mutationGene(Gene gene, int n) {
List<Integer> indexList = makeList(chromosomeSize);
for (int i = 0; i < n; i++) {
int a = indexList.remove(random.nextInt(indexList.size()));
int b = indexList.remove(random.nextInt(indexList.size()));
int t = gene.chromosome[a];
gene.chromosome[a] = gene.chromosome[b];
gene.chromosome[b] = t;
}
gene.fitness = calculateFitness(gene).fulfillTime;
return gene;
}
// 選擇個體
public Gene selectGene(int n) {
List<Integer> indexList = makeList(geneSet.size());
Map<Integer, Boolean> map = new HashMap<>();
for (int i = 0; i < n; i++) {
map.put(indexList.remove(random.nextInt(indexList.size())), true);
}
Gene bestGene = new Gene(0xfffff);
int i = 0;
for (Gene gene : geneSet) {
if (map.containsKey(i)) {
if (bestGene.fitness > gene.fitness) {
bestGene = gene;
}
}
i ++;
}
return bestGene;
}
public Result run(List<List<Integer[]>> job) {
int jobSize = job.size();
for (int i = 0; i < jobSize; i ++) {
chromosomeSize += job.get(i).size();
processNumber = Math.max(processNumber, job.get(i).size());
for (int j = 0; j < job.get(i).size(); j ++) {
machineMatrix[i][j] = job.get(i).get(j)[0];
timeMatrix[i][j] = job.get(i).get(j)[1];
}
}
for (int i = 0; i < jobSize; i++) {
for (int j = 0;j < processNumber; j++){
if (machineMatrix[i][j] != -1) {
processMatrix[i][machineMatrix[i][j]] = j;
}
}
}
initialPopulation();
for (int i = 0; i < populationNumber; i++) {
double p = (double) random.nextInt(100) / 100.0;
if (p < mutationProbability) {
int index = random.nextInt(geneSet.size());
int k = 0;
for (Gene gene : geneSet) {
if (k == index) {
mutationGene(gene);
break;
}
k ++;
}
} else {
Gene g1 = selectGene(), g2 = selectGene();
Gene child1 = crossGene(g1, g2), child2 = crossGene(g2, g1);
geneSet.add(child1);
geneSet.add(child2);
}
}
Gene bestGene = new Gene(0xffffff);
for (Gene gene : geneSet) {
if (bestGene.fitness > gene.fitness) {
bestGene = gene;
}
}
return calculateFitness(bestGene);
}
public Gene selectGene() {
return selectGene(3);
}
public Gene mutationGene(Gene gene) {
return mutationGene(gene, 2);
}
static public void main(String[] args) {
List<List<Integer[]>> job = Arrays.asList(
Arrays.asList(new Integer[]{0, 3}, new Integer[]{1, 2}, new Integer[]{2, 2}),
Arrays.asList(new Integer[]{0, 2}, new Integer[]{2, 1}, new Integer[]{1, 4}),
Arrays.asList(new Integer[]{1, 4}, new Integer[]{2, 3})
);
int n = 3, m = 3;
GeneticAlgorithm ga = new GeneticAlgorithm(n, m);
Result result = ga.run(job);
int processNumber = ga.processNumber;
int[][] machineMatrix = ga.machineMatrix;
System.out.println(result.fulfillTime);
for (int i = 0; i < n; i++) {
for (int j = 0 ; j < processNumber; j++) {
if (machineMatrix[i][j] != -1) {
System.out.println(String.format("job: %d, process: %d, machine: %d, startTime: %d, endTime: %d",
i, j, machineMatrix[i][j], result.startTime[i][j], result.endTime[i][j]));
}
}
}
}
}
class Gene {
public double fitness;
public Integer[] chromosome;
public Gene() {
fitness = 0;
}
public Gene(double fitness) {this.fitness = fitness;}
}
class Result {
public int fulfillTime = 0;
public int[] machineWorkTime = new int[1024];
public int[] processIds = new int[1024];
public int[][] endTime = new int[1024][1024];
public int[][] startTime = new int[1024][1024];
}複製代碼
寫了那麼多的遺傳算法解做業車間調度問題,固然還要有實際應用了,所以開發了一個做業車間調度系統,核心功能很簡單就是對工件、機器、工序進行增刪改查並使用遺傳算法計算調度結果,前端用甘特圖展現調度結果。(GitHub地址:github.com/sundial-dre…,若是以爲項目不錯,別忘了點贊哦)
系統整體技術路線:採用先後端分離模式開發,基於C/S模式,客戶端使用JavaScript,Electron, React,Node.js等進行組件化開發,服務端使用express,nodejs,typescript,python,sanic,graphql等開發獨立的graphql服務或http服務,數據庫使用mysql來存儲基本的信息,redis來實現id生成,mongodb來存儲調度結果。
Client端:使用JavaScript來開發PC端應用程序。基於Electron進行開發,在Electron基礎上使用React、Redux、Antd、Echarts等前端技術和包,以模塊化、組件化的方式構建一個獨立的UI頁面,對於頁面的切換使用了前端路由React-router。除此以外,經過封裝一個GraphQL類來作GraphQL查詢,以此和後端進行數據交互。經過這種方式能快速的構建一個可維護性好,UI美觀的PC端應用程序。
GrapgQL Service端:使用Typescript開發的一個GraphQL服務,提供GraphQL查詢。基於NodeJS、Express、GraphQL等來構建一個GraphQL服務器,因爲Node.js的異步非阻塞特性,使得構建的服務器併發能力更強。除此以外,使用TypeORM來作數據庫的對象關係映射,加快開發速度。經過這種方式能快速搭建起一個GraphQL服務端,使用GraphQL查詢來替代傳統的RESTful API能使提供的API服務可維護性、擴展性更強。
Schedule Service端:使用Python開發,提供做業調度服務。基於Python異步Web框架Sanic,使得構建的服務器運行效率和併發能力都比較強,而且使用Python來實現做業車間調度算法(遺傳算法)一方面是比較容易,另外一方面是Python支持多線程編程,所以多線程來優化算法也能實現。
Data Storage端:數據存儲,使用MySQL來存儲一些基本的數據,如機器信息、工件信息、工件工藝信息、員工信息等等。使用Redis來存儲一些健值對信息以及Id生成,因爲Redis的單線程異步非阻塞特性,使得生成的Id不存在重複。使用MongoDB來存儲調度結果,因爲調度結果徹底是JSON格式數據,與使用MySQL存儲相比,使用文檔數據庫MongoDB來存儲比較容易,並且查詢也比較方便。
項目運行:
首頁
管理
最後,若是以爲這篇文章有幫助,別忘了點贊哦