使用资源进行序列化并行操作

问题描述 投票:0回答:1

我有一个操作清单。每个操作使用一个资源。某些操作使用相同的资源。例如,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也无缘无故地等待。

有什么想法吗?

javascript async-await
1个回答
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"}
];

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]);
}
© www.soinside.com 2019 - 2024. All rights reserved.