web-dev-qa-db-ja.com

ブロッキングであるnodejsでスリープ/遅延を作成する方法は?

現在、nodejsを学ぼうとしていますが、私が取り組んでいる小さなプロジェクトでは、ネットワーク化されたLEDライトを制御するAPIを作成しています。

LEDを制御するマイクロプロセッサには処理遅延があり、マイクロに送信されるコマンドを少なくとも100ms離す必要があります。 C#では、Thread.Sleep(time)を呼び出すだけでしたが、ノードに同様の機能は見つかりませんでした。

ノードでsetTimeout(...)関数を使用するいくつかのソリューションを見つけましたが、これは非同期であり、スレッドをブロックしません(このシナリオで必要なものです)。

ブロッキングスリープまたは遅延機能を知っている人はいますか? CPUをスピンするだけでなく、精度が+ -10ミリ秒のものが望ましいですか?

50
on3al

最良の解決策は、すべてのコマンドをキューに入れて指定された遅延で実行するLEDのシングルトンコントローラーを作成することです。

function LedController(timeout) {
  this.timeout = timeout || 100;
  this.queue = [];
  this.ready = true;
}

LedController.prototype.send = function(cmd, callback) {
  sendCmdToLed(cmd);
  if (callback) callback();
  // or simply `sendCmdToLed(cmd, callback)` if sendCmdToLed is async
};

LedController.prototype.exec = function() {
  this.queue.Push(arguments);
  this.process();
};

LedController.prototype.process = function() {
  if (this.queue.length === 0) return;
  if (!this.ready) return;
  var self = this;
  this.ready = false;
  this.send.apply(this, this.queue.shift());
  setTimeout(function () {
    self.ready = true;
    self.process();
  }, this.timeout);
};

var Led = new LedController();

これでLed.execを呼び出すことができ、すべての遅延を処理します:

Led.exec(cmd, function() {
  console.log('Command sent');
});
39

Nodeは本質的に非同期であり、それは素晴らしいことなので、本当にスレッドをブロックするべきではありませんが、これはLEDを制御するプロジェクトのように見えるので、とにかくワークアラウンドを投稿します。良いものと使用しないでください(真剣に)。

Whileループはスレッドをブロックするため、独自のスリープ関数を作成できます

function sleep(time, callback) {
    var stop = new Date().getTime();
    while(new Date().getTime() < stop + time) {
        ;
    }
    callback();
}

として使用される

sleep(1000, function() {
   // executes after one second, and blocks the thread
});

Nodeにはブロッキング機能が組み込まれていないため、スレッドをブロックする唯一の方法であり(原則として)、スレッドをビジー状態に保ちます。非同期動作。

61
adeneo

Node sleepパッケージを使用します。 https://www.npmjs.com/package/sleep

あなたのコードで使用できます

var sleep = require('sleep'); 
sleep.sleep(n)

特定のn秒間スリープします。

28
Manoj Sanjeewa

child_process.execSyncを使用して、システムのスリープ関数を呼び出すだけです。

//import child_process module
const child_process = require("child_process");
// Sleep for 5 seconds
child_process.execSync("sleep 5");

// Sleep for 250 microseconds
child_process.execSync("usleep 250");

// Sleep for a variable number of microseconds
var numMicroSeconds = 250;
child_process.execFileSync("usleep", [numMicroSeconds]);

これをメインアプリケーションスクリプトの先頭のループで使用して、ネットワークドライブが接続されるまでNodeを待機させてから、アプリケーションの残りを実行します。

20
sffc

ECMAスクリプト2017(Node 7.6以降でサポート)では、1行になります。

function sleep(millis) {
  return new Promise(resolve => setTimeout(resolve, millis));
}

// Usage in async function
async function test() {
  await sleep(1000)
  console.log("one second has elapsed")
}

// Usage in normal function
function test2() {
  sleep(1000).then(() => {
    console.log("one second has elapsed")
  });
}
11
HRJ

最も簡単な真の同期ソリューション(つまり、yield/asyncなし)依存関係のないすべてのOSで機能することを思い付くことができるのは、ノードプロセスを呼び出してインラインsetTimeout式を評価することです。

const sleep = (ms) => require("child_process")
    .execSync(`"${process.argv[0]}" -e setTimeout(function(){},${ms})`);
4
mythz

ネイティブアドオンで実装するのは非常に簡単なので、誰かがそれを行いました: https://github.com/ErikDubbelboer/node-sleep.git

2
vkurchatkin

私はここでほとんど機能しているものを見つけました https://stackoverflow.com/questions/21819858/how-to-wrap-async-function-calls-into-a-sync-function-in-node-js-or- ja vascript

`function AnticipatedSyncFunction(){
    var ret;
    setTimeout(function(){
        var startdate = new Date()
        ret = "hello" + startdate;
    },3000);
    while(ret === undefined) {
       require('deasync').runLoopOnce();
    }
    return ret;    
}


var output = AnticipatedSyncFunction();
var startdate = new Date()
console.log(startdate)
console.log("output="+output);`

固有の問題は、印刷された日付が正しくないが、少なくともプロセスがシーケンシャルであることです。

2
Alex

厳しいハードウェアソリューションを開発する場合でも、Node.jsでのブロックは不要です。 temporal.js を参照してください。これはsetTimeoutまたはsetIntervalsetImmediateを使用しません。代わりに、 setImmediate またはnextTickを使用して、より高い解像度のタスク実行を提供し、タスクの線形リストを作成できます。ただし、スレッドをブロックせずに実行できます。

1
Brian Genisio

ECMA6で導入されたyield機能とgen-runライブラリを単に使用できます。

let run = require('gen-run');


function sleep(time) {
    return function (callback) {
        setTimeout(function(){
            console.log(time);
            callback();
        }, time);
    }
}


run(function*(){
    console.log("befor sleeping!");
    yield sleep(2000);
    console.log("after sleeping!");
});
0
NaWeeD