有比使用嵌套循环更好的查找解决方案的方法吗?

问题描述

我希望基于所包含的代码中的嵌套循环加快测试所有组合的过程。

我目前在Windows 10上仍然使用JavaScript和NodeJS。

有没有一种方法可以使用GPU而不是cpu进行计算?

var simulations = 0;
for (let i = 10; i <= 20; i++) {
    breakStepThree = i;
    for (let i = 8; i <= 12; i++) {
        historyLevelThree = i;
        for (let i = 0; i <= 60; i += 5) {
            rateLevelThree = i;
            for (let i = 10; i <= 16; i++) {
                breakStepTwo = i;
                for (let i = 6; i <= 10; i++) {
                    historyLevelTwo = i;
                    for (let i = 0; i <= 50; i += 5) {
                        rateLevelTwo = i;
                        for (let i = 10; i <= 14; i++) {
                            breakStepOne = i;
                            for (let i = 4; i <= 8; i++) {
                                historyLevelOne = i;
                                for (let i = 0; i <= 40; i += 5) {
                                    rateLevelOne = i;
                                    simulations++;
                                    console.log('testing combination '
                                        + rateLevelOne + ' ' + historyLevelOne + ' ' + breakStepOne + ' '
                                        + rateLevelTwo + ' ' + historyLevelTwo + ' ' + breakStepTwo + ' '
                                        + rateLevelThree + ' ' + historyLevelThree + ' ' + breakStepThree
                                    );
                                    console.log('performing test no ' + simulations);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

尽我所能执行工作线程。

const {
    Worker,isMainThread,parentPort,workerData
} = require('worker_threads');

const os = require('os');

if (isMainThread) {
    const startTime = Date.Now();

    const workers = [];

    // const numberOfThreads = 1;
    const numberOfThreads = os.cpus().length;

    let completed = 0;

    let minBreakStep = 10;
    let maxBreakStep = 20;
    let minMaxElements = [];

    for (let i = minBreakStep; i <= maxBreakStep; i++) {
        minMaxElements.push(i);
    }

    const numberOfElements = minMaxElements.length;

    const numElementsPerThread = Math.ceil(numberOfElements / numberOfThreads);

    let workerIndex = 0;

    let allSimulations = 0;

    for (let i = minBreakStep; i <= maxBreakStep; i += numElementsPerThread) {
        let workerStart = i;
        let workerEnd = i + numElementsPerThread - 1;
        if (workerEnd > maxBreakStep) {
            workerEnd = maxBreakStep
        }

        const worker = new Worker(__filename,{
            workerData: {
                workerIndex,workerStart,workerEnd,}
        });

        worker.on('message',(message) => {
            if (message.completed) {
                completed++;
                console.log('worker ' + message.workerIndex + ' completed ' + message.simulations + ' simulations.');
                allSimulations += message.simulations;
            }
            if (completed === workers.length) {
                console.log('Completed all ' + allSimulations + ' done!');
                const endTime = Date.Now();
                const elapsedtime = (endTime - startTime) / 1000;
                console.log(elapsedtime + ' second(s) to complete');
            }
        });
        workerIndex++;
        workers.push(worker);
    }

} else {

    let workerIndex = workerData.workerIndex;
    let workerStart = workerData.workerStart;
    let workerEnd = workerData.workerEnd;

    let simulations = 0;

    for (let i = workerStart; i <= workerEnd; i++) {
        breakStepThree = i;
        for (let i = 8; i <= 12; i++) {
            historyLevelThree = i;
            for (let i = 0; i <= 60; i += 5) {
                rateLevelThree = i;
                for (let i = 10; i <= 16; i++) {
                    breakStepTwo = i;
                    for (let i = 6; i <= 10; i++) {
                        historyLevelTwo = i;
                        for (let i = 0; i <= 50; i += 5) {
                            rateLevelTwo = i;
                            for (let i = 10; i <= 14; i++) {
                                breakStepOne = i;
                                for (let i = 4; i <= 8; i++) {
                                    historyLevelOne = i;
                                    for (let i = 0; i <= 40; i += 5) {
                                        rateLevelOne = i;
                                        simulations++;
                                        // console.log('testing combination '
                                        //     + rateLevelOne + ' ' + historyLevelOne + ' ' + breakStepOne + ' '
                                        //     + rateLevelTwo + ' ' + historyLevelTwo + ' ' + breakStepTwo + ' '
                                        //     + rateLevelThree + ' ' + historyLevelThree + ' ' + breakStepThree
                                        // );
                                        // console.log('performing test no ' + simulations);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    console.log('testing completed');
    parentPort.postMessage({
        completed: true,workerIndex: workerIndex,simulations: simulations,});
}

解决方法

在Node.js中,我不知道任何易于使用的GPU。根据测试每种组合的工作性质和主机系统的特性,您可以使用内置的worker_threads和/或cluster模块来分散工作。 worker_threads模块在​​进程内创建线程。 cluster模块创建单独的进程。

,

尽我所能执行工作线程。

const {
    Worker,isMainThread,parentPort,workerData
} = require('worker_threads');

const os = require('os');

if (isMainThread) {
    const startTime = Date.now();

    const workers = [];

    // const numberOfThreads = 1;
    const numberOfThreads = os.cpus().length;

    let completed = 0;

    let minBreakStep = 10;
    let maxBreakStep = 20;
    let minMaxElements = [];

    for (let i = minBreakStep; i <= maxBreakStep; i++) {
        minMaxElements.push(i);
    }

    const numberOfElements = minMaxElements.length;

    const numElementsPerThread = Math.ceil(numberOfElements / numberOfThreads);

    let workerIndex = 0;

    let allSimulations = 0;

    for (let i = minBreakStep; i <= maxBreakStep; i += numElementsPerThread) {
        let workerStart = i;
        let workerEnd = i + numElementsPerThread - 1;
        if (workerEnd > maxBreakStep) {
            workerEnd = maxBreakStep
        }

        const worker = new Worker(__filename,{
            workerData: {
                workerIndex,workerStart,workerEnd,}
        });

        worker.on('message',(message) => {
            if (message.completed) {
                completed++;
                console.log('worker ' + message.workerIndex + ' completed ' + message.simulations + ' simulations.');
                allSimulations += message.simulations;
            }
            if (completed === workers.length) {
                console.log('Completed all ' + allSimulations + ' done!');
                const endTime = Date.now();
                const elapsedTime = (endTime - startTime) / 1000;
                console.log(elapsedTime + ' second(s) to complete');
            }
        });
        workerIndex++;
        workers.push(worker);
    }

} else {

    let workerIndex = workerData.workerIndex;
    let workerStart = workerData.workerStart;
    let workerEnd = workerData.workerEnd;

    let simulations = 0;

    for (let i = workerStart; i <= workerEnd; i++) {
        breakStepThree = i;
        for (let i = 8; i <= 12; i++) {
            historyLevelThree = i;
            for (let i = 0; i <= 60; i += 5) {
                rateLevelThree = i;
                for (let i = 10; i <= 16; i++) {
                    breakStepTwo = i;
                    for (let i = 6; i <= 10; i++) {
                        historyLevelTwo = i;
                        for (let i = 0; i <= 50; i += 5) {
                            rateLevelTwo = i;
                            for (let i = 10; i <= 14; i++) {
                                breakStepOne = i;
                                for (let i = 4; i <= 8; i++) {
                                    historyLevelOne = i;
                                    for (let i = 0; i <= 40; i += 5) {
                                        rateLevelOne = i;
                                        simulations++;
                                        // console.log('testing combination '
                                        //     + rateLevelOne + ' ' + historyLevelOne + ' ' + breakStepOne + ' '
                                        //     + rateLevelTwo + ' ' + historyLevelTwo + ' ' + breakStepTwo + ' '
                                        //     + rateLevelThree + ' ' + historyLevelThree + ' ' + breakStepThree
                                        // );
                                        // console.log('performing test no ' + simulations);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    console.log('testing completed');
    parentPort.postMessage({
        completed: true,workerIndex: workerIndex,simulations: simulations,});
}
,

例如,您可以使用CUDA绑定在GPU上执行计算。也许在这种情况下,最好是连接C程序并导入/导出实验设计和结果。 https://github.com/kashif/node-cuda / https://www.npmjs.com/package/cuda-node-js

此外,我将使用以下类似的方法摆脱所有这些嵌套循环。为了性能起见,可以放弃切片,并检查参数,因为以下几行仅是为了让大家明白这一点。

class ExperimentGenerator{

  let pointer = 0;
  const initialParams = [0,0];
  let params = [...initialParams]
  const maxValue = [10,10,10]

  nextExperiment = () =>{
     if(params[pointer] >= maxValue[pointer]){
         pointer++;
         //Reset all other parameters
         params = [initialParams.slice(0,pointer),params[pointer],initialParams.slice(pointer)];
     }
     params[pointer]++;
     return params;
  }
}