在Node.js中,如何asynchronous创buildsha512哈希?

var crypto = require('crypto'); var sha = crypto.createHash('sha512').update(String(s)); var result = sha.digest('hex'); 

这是我现在的代码。

我如何做这个asynchronous? 我打算做10万次。

如果你找不到更好的解决scheme,这个技巧可以帮助你:

您可以创build一个独立的SHA-512生成器应用程序,它接收您的string“s”作为标准input,生成散列,并将其写入标准输出。

从你的应用程序中,你可以通过child_process模块来执行它,并用事件处理程序捕获响应。 还有一个其他的stackoverflow线程,可能会在child_process方便的使用:

  • 是否有可能从节点js执行外部程序?

这样你可以把同步函数封装到一个asynchronous的上下文中。 🙂

节点的crypto模块目前不提供asynchronousSHA512散列,尽pipecreateHash()stream接口看起来是asynchronous的,但它也将在主线程中执行并阻塞事件循环。

有一个问题打开: https : //github.com/nodejs/node/issues/678

在此期间,您可以使用@ronomon/crypto-async@ronomon/crypto-asyncasynchronous并发地执行SHA512,而不会阻塞事件循环,从而实现多核吞吐量。

Node.js在一个线程中运行,所以如果你想做asynchronous处理,你必须:

  • 使用本地执行线程的模块;
  • 产生多个Node.js进程。

我在下面介绍的方法使用后一种方法。

Node.js API提供了一个名为cluster的模块,它允许你像在C中编程一样分叉进程。

我的做法是将input数据(要散列的string)分解为块,其中每个块都传递给子工作进程。 当工作人员完成其大块工作时,它会发出主进程的信号,并将结果传递回去。

主节点在工作人员完成工作的同时继续运行,因此可以在不被阻塞的情况下执行任何不相关的asynchronous工作。 所有工作人员完成后,主人发出信号,并可自由进一步处理最终结果。

运行我的testing,你可以简单地做:

 node parhash 

我的testing运行在具有8 GB RAM DDR3的Intel Core i5 4670上。

为了你需要100000个string,1个工人在450毫秒内完成,而10个工人需要350毫秒

在一个百万string的testing中,1名工作者在4.5秒内完成了工作,而10名工作者在3.5秒内完成了这项工作。

这里是代码:

parhash.js

 var crypto = require('crypto'), cluster = require('cluster'); var STRING_COUNT = 1000000, STRINGS_PER_WORKER = 100000, WORKER_COUNT = Math.ceil(STRING_COUNT / STRINGS_PER_WORKER), chunks = [], nextChunkId = 0, results = [], startTime, pendingWorkers = WORKER_COUNT; /** * Generates strings partitioned in WORKER_COUNT chunks. * Each of these chunks will later be passed to a child process to be parsed asynchronously. * * You should replace this with your working data. */ function generateDemoStringChunks() { var si, wi, chunk; for (wi = 0; wi < WORKER_COUNT; wi++) { chunk = []; for (si = STRINGS_PER_WORKER * wi; (si < STRINGS_PER_WORKER * (wi + 1)) && (si < STRING_COUNT); si++) { chunk.push(si.toString()); } chunks.push(chunk); } } /** * After all workers finish processing, this will be executed. * * Here you should do whatever you want to process the resulting hashes. */ function mergeResults() { results.sort(function compare(a, b) { return a.id - b.id; }); console.info('Summary:'); results.forEach(function (result) { console.info('\tChunk %d: %d hashes (here is the first hash: "%s")', result.id, result.data.length, result.data[0]); }); } /** * This will be called on the master side every time a worker finishes working. * * @param {object} worker the Worker that finished * @param {{id: number, data: [string]}} result the result */ function processWorkerResult(worker, result) { console.info('Worker %d finished computing %d hashes.', worker.id, result.data.length); results.push(result); worker.kill(); if (--pendingWorkers == 0) { console.info('Work is done. Whole process took %d seconds.', process.hrtime(startTime)[0]); mergeResults(); } } /** * Gets a chunk of data available for processing. * * @returns {{id: number, data: [string]}} the chunk to be passed to the worker */ function getNextAvailableChunk() { var chunk = { id: nextChunkId, data: chunks[nextChunkId] }; nextChunkId++; return chunk; } /** * The master node will send a chunk of data every time a worker node * signals it's ready to work. */ function waitForWorkers() { cluster.on('online', function (worker) { console.info('Worker %d is online.', worker.id); worker.on('message', processWorkerResult.bind(null, worker)); worker.send(getNextAvailableChunk()); }); } /** * Start workers. */ function spawnWorkers() { var wi; for (wi = 0; wi < WORKER_COUNT; wi++) { cluster.fork(); } } /** * The hash function. * * @param {string} sa string to be hashed * @returns {string} the hash string */ function hashString(s) { return crypto.createHash('sha512').update(s).digest('hex'); } /** * A worker will wait for the master to send a chunk of data and will * start processing as soon as it arrives. */ function processChunk() { cluster.worker.on('message', function(chunk) { var result = []; console.info('Worker %d received chunk %d with a load of %d strings.', cluster.worker.id, chunk.id, chunk.data.length); chunk.data.forEach(function processChunk(s) { result.push(hashString(s)); }); cluster.worker.send({ id: chunk.id, data: result }); }); } function main() { if (cluster.isMaster) { /* The master node will instantiate all required workers and then pass a chunk of data for each one. It will then wait for all of them to finish so it can merge the results. */ startTime = process.hrtime(); generateDemoStringChunks(); spawnWorkers(); waitForWorkers(); } else { /* A worker node will wait for a chunk to arrive and then will start processing it. When finished, it will send a message back to the master node with the resulting hashes. */ console.info('Worker %d is starting.', cluster.worker.id); processChunk(); } } main(); 

如果它是使用线程实现的,我无法判断它的执行情况,因为我没有对它进行testing。 如果你想做一个基准testing,你可以试试WebWorker Threads (注意:我还没有尝试WebWorkers模块,但我不能保证它能正常工作 – 你自己在这里)