我有一个操作清单。每个操作使用一个资源。某些操作使用相同的资源。 例如,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也无缘无故地等待。
有什么想法吗?
答案 0 :(得分:1)
您可以执行以下操作。
注意-可以以更优化的方式编写此代码。这只是一个想法。
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", startedAt: 0},
{name: "op2", operation: op2, resource: "R2", startedAt: 0},
{name: "op3", operation: op3, resource: "R1", startedAt: 0},
{name: "op4", operation: op4, resource: "R4", startedAt: 0},
{name: "op5", operation: op5, resource: "R5", startedAt: 0}
];
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) {
if (operation.startedAt === 0) {
operation.startedAt = 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 - operation.startedAt).toFixed(2)} milliseconds`);
if (Array.isArray(resources[operation.resource].queue) && resources[operation.resource].queue.length > 0) {
operationExecutor(resources[operation.resource].queue.splice(0, 1)[0]);
}
}
}
for (let i = 0; i < operations.length; i++) {
(operationExecutor)(operations[i]);
}
答案 1 :(得分:1)
鉴于这些操作互不依赖于彼此的结果,您可以为每个资源创建并发队列,然后依次依次执行每个操作:
const opsByResource = new Map()
for (const op in operations) {
const r = op.usedResource
if (!opsByResource.has(r)) opsByResource.put(r, [])
opsByResource.get(r).push(op)
}
return Promise.all(Array.from(opsByResource, async ([res, ops]) => {
for (const op in ops)
await perform(op)
console.log("Done with all operations on", res)
}))
答案 2 :(得分:0)
受您的解决方案启发,我这样做是这样的:
我广泛使用受控承诺的实现,这是带有公开的“ resolveTo”函数并具有指定超时后自动解析选项的常规承诺。我想知道是否有人使用类似的东西,我个人无法想象没有它的编程。