我有一个操作清单。每个操作使用一个资源。某些操作使用相同的资源。例如,op1使用与op3相同的资源。符号代码:
operations=[op1,op2,op3,op4,op5]
for (let i=0;i<operations.length;i++) {
perform(operations[i])
}
失败,因为op1和op3使用相同的资源。因此,另一个方法是:
operations=[op1,op2,op3,op4,op5]
for (let i=0;i<operations.length;i++) {
await perform(operations[i])
}
不会失败,但是op2不必等待o1完成,即使它们没有使用相同的资源。
其他方法:
operations=[op1,op2,op3,op4,op5]
for (let i=0;i<operations.length;i++) {
await operations[i].usedResource.isAvailable;
perform(operations[i])
}
[确定,运行op1,运行op2,op3等待被op1阻塞的资源,...但是op4和op5也无缘无故地等待。
有什么想法吗?
您可以做这样的事情。
注意-此代码可以以更优化的方式编写。这只是一个想法。
let operation = (operation, time) => () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, time);
});
};
let op1 = operation("op1", 10000);
let op2 = operation("op2", 2000);
let op3 = operation("op3", 2000);
let op4 = operation("op4", 1000);
let op5 = operation("op5", 5000);
const operations = [
{name: "op1", operation: op1, resource: "R1"},
{name: "op2", operation: op2, resource: "R2"},
{name: "op3", operation: op3, resource: "R1"},
{name: "op4", operation: op4, resource: "R4"},
{name: "op5", operation: op5, resource: "R5"}
];
const isResourceAvailable = (config) => {
return new Promise((resolve) => {
(function waitForResource() {
if (config.available) {
return resolve();
}
setTimeout(waitForResource, 30);
})();
});
};
let resources = {
"R1": {
available: true,
usedBy: "",
isResourceAvailable
},
"R2": {
available: true,
usedBy: "",
isResourceAvailable
},
"R3": {
available: true,
usedBy: "",
isResourceAvailable
},
"R4": {
available: true,
usedBy: "",
isResourceAvailable
},
"R5": {
available: true,
usedBy: "",
isResourceAvailable
},
};
for (let i = 0; i < operations.length; i++) {
setTimeout(() => {
(async function (operation) {
const t0 = performance.now();
console.log("Initiated", operation.name);
await resources[operation.resource].isResourceAvailable(resources[operation.resource]);
console.log("Started", operation.name);
resources[operation.resource].available = false;
await operation.operation();
const t1 = performance.now();
resources[operation.resource].available = true;
console.log("Completed", operation.name, `in ${(t1 - t0).toFixed(2)} milliseconds`);
})(operations[i])
}, 0);
}
使用队列的另一种方法(更有效):
let operation = (operation, time) => () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, time);
});
};
let op1 = operation("op1", 10000);
let op2 = operation("op2", 2000);
let op3 = operation("op3", 2000);
let op4 = operation("op4", 1000);
let op5 = operation("op5", 5000);
const operations = [
{name: "op1", operation: op1, resource: "R1"},
{name: "op2", operation: op2, resource: "R2"},
{name: "op3", operation: op3, resource: "R1"},
{name: "op4", operation: op4, resource: "R4"},
{name: "op5", operation: op5, resource: "R5"}
];
let resources = {
"R1": {
isAvailable: true,
queue: []
},
"R2": {
isAvailable: true,
queue: []
},
"R3": {
isAvailable: true,
queue: []
},
"R4": {
isAvailable: true,
queue: []
},
"R5": {
isAvailable: true,
queue: []
},
};
async function operationExecutor(operation) {
const t0 = performance.now();
if (!resources[operation.resource].isAvailable) {
console.log("Operation", operation.name, "waiting for Resource", operation.resource);
resources[operation.resource].queue.push(operation);
} else {
console.log("Operation Started", operation.name);
resources[operation.resource].isAvailable = false;
console.log("Resource locked", operation.resource);
await operation.operation();
const t1 = performance.now();
console.log("Resource released", operation.resource);
resources[operation.resource].isAvailable = true;
console.log("Operation Completed", operation.name, `in ${(t1 - t0).toFixed(2)} milliseconds`);
if (Array.isArray(resources[operation.resource].queue) && resources[operation.resource].queue.length > 0) {
setTimeout(() => {
operationExecutor(resources[operation.resource].queue.splice(0, 1)[0]);
}, 0);
}
}
}
for (let i = 0; i < operations.length; i++) {
(operationExecutor)(operations[i]);
}