質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

3回答

2080閲覧

javascriptのwaitに関する質問です。

neil

総合スコア25

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

2クリップ

投稿2017/02/06 21:09

編集2017/02/06 23:46

###前提・実現したいこと

以下のコードでサーバーのGPUの状態をsshコマンドを用いて
得ようとしているのですが、arrayの中身がundefiedであるというエラーがでてうまくいきません。
問題点は、まだarrayの中に情報が入っていないのにもかかわらず、
sliceをしてしまっていることです。
解決法として、arrayの中にきちんと要素が入ってから
slice処理を行うということをしたいのですが、
どのようにすれば良いのかわかりません。

よろしくお願いします。
###発生している問題・エラーメッセージ

Uncaught TypeError: Cannot read property 'slice' of undefined

###該当のソースコード

function query_gpu(gpu_name, array){ var SSH = require('simple-ssh'); var ssh = new SSH({ host: gpu_name, user: 'name', pass: 'pass' }); ssh.exec('nvidia-smi --query-gpu=utilization.gpu --format=csv', { out: function(stdout) { array.push(stdout) console.log(stdout) } }).start() } var a = []; query_gpu('tai', a); array[1] = Number(array[1].slice(0,2)); array[2] = Number(array[2].slice(0,2));

###試したこと
// Mixing jQuery and Node.js code in the same file? Yes please!

$(function(){

function query_gpu(gpu_name, array, callback) {

var SSH = require('simple-ssh');
var ssh = new SSH({
host: gpu_name,
user: 'name',
pass: 'pass'
});

ssh.exec('nvidia-smi --query-gpu=utilization.gpu --format=csv', {
out: function(stdout) {
array.push(stdout)
debugger;
console.log(stdout)
callback();
}
}).start()
}

var a = [];
query_gpu('tai', a, function() {
// ここに取得したデータについての処理を全て書く
a[1] = Number(a[1].slice(0, 2));
a[2] = Number(a[2].slice(0, 2));
});

});

を走らせてみて途中のstdoutの結果を見ました。
'''
utilization.gpu [%]
0 %
99 %
'''
と複数行で3つの値が来ることを期待していたのですが、実際は初めのutilization.gpu [%]だけでした。

###補足情報(言語/FW/ツール等のバージョンなど)
nodeのsimple-ssh

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

turbgraphics200

2017/02/06 21:58

JSでsshコマンドを実行するということは何らかのライブラリやツールを使用していると思いますが、使用しているライブラリもしくはツールを記載してください。
turbgraphics200

2017/02/06 22:54

あと、nvidia-smi --query-gpu=utilization.gpu --format=csv を実行した、実際の標準出力の結果を記載してください。
neil

2017/02/06 23:11

sshを使用しているライブラリーはnodeのsimple-sshというものです。nvidia-smi --query-gpu=utilization.gpu --format=csvの出力結果はutilization.gpu [%] 0 % 97 %というような3つのstringです。
turbgraphics200

2017/02/06 23:19

このコメントにではなく、質問内容に追加してください。また、出力結果はコピペしてそのまま記載してください
turbgraphics200

2017/02/06 23:42

出力結果は utilization.gpu [%] 0 % 97 % が一行となるのでしょうか。それとも複数行になるのでしょうか。出力結果はわかりやすくコードと同様に```で囲ってください。
neil

2017/02/06 23:47

コマンドラインで打つと複数行になります
kei344

2017/02/07 02:15

質問文のコードはそれぞれコードブロックで囲んでいただけませんか? ```(バッククオート3つ)で囲み、前後に改行をいれるか、コードを選択して「<code>」ボタンを押すとコードブロックになります。
guest

回答3

0

JavaScriptにはwaitという概念はありません。ファイルやDBの取得や実行、通信などの通常は待ちが発生するような処理は、開始と共にバックグラウンドで行われ、終了を待たずに次のコードへ進みます。これを非同期処理と言います。取得内容を使用するには、ファイルの取得等が終了した後に実行されるコールバック関数で全ての処理をする必要があります。

※ Node.jsのfs等には、処理を待ってくれるsync系のメソッドも一部だけ存在します。

simple-sshも同様で、コールバック内でしか、その結果を利用できません。今回のコードでは、outで指定しているコールバック内で全て処理するか、処理する関数をコールバック内から呼び出す必要があります。次のように書きかえれば、sshでの取得内容を利用できるようになります。

JavaScript

1function query_gpu(gpu_name, array, callback) { 2 var SSH = require('simple-ssh'); 3 var ssh = new SSH({ 4 host: gpu_name, 5 user: 'name', 6 pass: 'pass' 7 }); 8 9 ssh.exec('nvidia-smi --query-gpu=utilization.gpu --format=csv', { 10 out: function(stdout) { 11 array.push(stdout) 12 console.log(stdout) 13 callback(); 14 } 15 }).start() 16} 17 18var a = []; 19query_gpu('tai', a, function() { 20 // ここに取得したデータについての処理を全て書く 21 a[1] = Number(a[0].slice(0, 2)); 22 a[2] = Number(a[0].slice(0, 2)); 23}); 24

これではコールバックがどんどん深くなって、コールバックだらけになるのでは無いのか?と思うかも知れません。その通りです。これはいわゆるコールバック地獄と言われるもので、JavaScriptのコードをわかりにくいものにするものの一つと言われています。これを解決するにはPromise等を使う必要があります。Promiseの使い方は色々と文献がありますので、調べてみてください。

まとめると次のようになります。

  • IOや実行、通信等の待ちが発生するような処理をJavaScriptは待ってくれず、非同期で行う。
  • その結果はコールバック内(またはコールバックから呼び出した関数内)でしか利用できない。
  • コールバックだらけになるコールバック地獄を解消するには、Promise等を使う必要がある。

投稿2017/02/06 22:06

raccy

総合スコア21735

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

neil

2017/02/06 23:24

丁寧な回答ありがとうございます。 コードをデバッグモードで走らせてみました。 期待していたのはstdoutの中にutilization.gpu [%] 0 % 97 %があることを期待していたのですが、 実際の中身はutilization.gpu [%] だけでした。arrayの中身もutilization.gpu [%]だけでした。 全てをarrayの中に入れるにはどうしたら良いでしょうか? よろしくお願いします。
raccy

2017/02/07 10:09

うーん、ちょっとわからないですね…。SSHが失敗したのかsimple-sshがおかしいのか、一行ずつ取ってくるのか…。 turbgraphics200さんの回答通りだと、全部返ってくるはずですが、もしかしたら、一行ずつなのかもしれません。一行ずつとるのであれば、別途カウントしながら、全部終わったら(カウントが一定値になったら)、callback()を呼ぶとかにするといいかと思います。
guest

0

ベストアンサー

outが非同期で呼ばれるからというのはすでに前者の回答者により説明がありましたが。
実際このoutの関数がどのように呼ばれるのか、特に標準出力の結果の1行ごとに複数回呼ばれるのか、すべての行一括にして一回で呼ばれるのかによって違うかと思います。
一応自分の環境でこのsimple-sshを試してみたら、nvidiaマシンではないのでこのコマンドは使えませんので代わりにlsコマンドを実行してみたら、標準出力結果を全行一括で1回のみ呼ばれました。もしかするとコマンドによって違うかもしれませんが。

js

1function query_gpu(gpu_name, array) { 2 return new Promise((resolve, reject) => { 3 4 var SSH = require('simple-ssh'); 5 var ssh = new SSH({ 6 host: gpu_name, 7 user: 'name', 8 pass: 'pass' 9 }); 10 11 ssh.exec('nvidia-smi --query-gpu=utilization.gpu --format=csv', { 12 out: function (stdout) { 13 if (stdout.includes('\n')) { 14 // stdoutが全行の場合 15 array = stdout 16 .split('\n') 17 .filter(v => !!v.trim() && !v.includes('utilization.gpu')) 18 .map(v => v.split(' ')) 19 .filter(v => !isNaN(v[0])) 20 .map(v => +v[0]); 21 } else { 22 // stdoutが1行ずつの場合 23 if (stdout.includes('utilization.gpu')) return; 24 var arr = stdout.split(' ').filter(v => v.trim()); 25 if (!arr.length || isNaN(arr[0])) return; 26 array.push(+arr[0]); 27 } 28 }, 29 exit: function () { 30 funcResult(array); 31 } 32 }).start(); 33 }); 34} 35 36function funcResult(array) { 37 console.log(array); 38} 39 40query_gpu('tai', []);

投稿2017/02/07 04:38

編集2017/02/07 10:18
turbgraphics200

総合スコア4267

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

raccyさんの助言通りでできるはずなので、コールバックが正確に行われているか、データが本当に代入されたか確認してみた方が良いですね。

それと、proxy使ってwatchするというやり方もなくはないのですが、遊んでみるのも楽しそうですね!
参考:Proxy - MDN

投稿2017/02/07 01:16

Everatch

総合スコア241

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問