ES6 Promiseのメモ

非同期処理のスマートな書き方の1つの解として注目を集めているPromise。

Deferredとか呼ばれたり、実装によってメソッド名とか仕組みとかが微妙に違ったり、しょうがないことですが言語仕様次第で実装方法が変わったりと、今ひとつ安定しないデザパタですが、コアコンセプトはES6のPromiseで抑えておくのが良いんじゃないかなと思います。

// 普通の実装
function incrementAsyncCallback(n, callback) {
  setTimeout(function() {
    callback(n+1);
  }, 100);
}

// thenメソッドを持つ(=thenable)オブジェクトを返す実装。
function incrementAsyncThenable(n) {
  var then;
  setTimeout(function() {
    if (then) then(n+1);
  }, 100);
  return {
    then: function(callback) {
      then = callback;
    }
  };
}

// ES6 Promiseを利用した実装
function incrementAsyncPromise(n) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      resolve(n+1);
    });
  });
}

// 上述の非同期関数をPromiseで逐次的に実行する例
Promise.resolve(1)
.then(function(n) {
  // Promiseでラップしてあげればthenで繋げられる
  return new Promise(function(resolve, reject) {
    incrementAsyncCallback(n, function(n) {
      resolve(n);
    });
  });
})
.then(function(n) {
  // thenableなオブジェクトを返す場合はPromise.resolve
  return Promise.resolve(incrementAsyncThenable(n));
})
.then(incrementAsyncPromise) // Promise返すなら何もする必要ない
.then(function(n) {
  console.log(n); // => 4
});

Mac OS Xには/procが無いのでsysctl使う

Linuxにはprocfsという"/proc"以下にシステム情報をファイルで配置してくれる仮想ファイルシステムがあり、CPUやメモリやプロセスその他もろもろの情報を調べるときに重宝します。

一方、Mac OSもといDarwinは、BSD系をベースにしており、またSUSによるUNIX認定を受けていますが、procfsは無いんですね。どうもprocfsはSUSの要件に入っていないようです。

もっとも、procfsが無くても、CPUのコア数とかメモリ容量とか調べるぐらいなら、アップルメニューから「このMacについて」を押せば概要が見れますし、もっと見たければ「詳しい情報...」を押せばその名の通り詳しい情報が出ますし、さらにもっと見たければ「システムレポート」を押せば「システム情報」というアプリが起動してハードウェアの詳細情報を全部見れます。システム情報アプリ(System Information.app)は、SpotlightとかAlfredで"sys"とでも入れれば出てくるので、起動はそれ程面倒ではないし、なにより情報が非常に見やすいです。

が、「いやGUIとかないでしょ」という人とか、「プログラムで取得したいんだが」みたいな需要は少なからずあると思うんですよね。なのに"/proc"が無い……この絶望感。

ということで少しググってみると、なんてことはない、普通にsysctlコマンドで取れることが判明しました。sysctl(8)自体はLinuxにもありますが、システムパラメータを変更するためのコマンドだと思ってた上、カーネルパラメータの変更は普通にprocfsで出来るので使ったことが無かったのですが*1、単に情報を取得することも出来たのですね。

このsysctlですが、Management Information Base(MIB)とかいう規格*2に準拠しているようで、つまるところツリー構造で情報が管理されているようです。

Macではハードウェア関係の情報は"hw"というツリーに入っているので、そこからメモリ容量とかを確認できます。"kern"ではカーネルのバージョン情報とかも取得できます。

$ sysctl hw | head
hw.ncpu: 4
hw.byteorder: 1234
hw.memsize: 8589934592
hw.activecpu: 4
hw.physicalcpu: 2
hw.physicalcpu_max: 2
hw.logicalcpu: 4
hw.logicalcpu_max: 4
hw.cputype: 7
hw.cpusubtype: 4
$ sysctl -n hw.memsize
8589934592
$ sysctl kern.version
kern.version: Darwin Kernel Version 13.1.0: Wed Apr  2 23:52:02 PDT 2014; root:xnu-2422.92.1~2/RELEASE_X86_64

これは楽しい!

ちなみに、システム情報アプリレベルの粒度の情報はsystem_profilerコマンドで取得できます。ただ、取得にちょっと時間がかかるのがネックなので、詳細な情報を必要としないならsysctlで十分だと思います。

*1:Linuxのsysctlはprocfsがベースみたいなのでsysctl使う必要性はやっぱり無い

*2:ネットワーク機器とかの情報管理で使われているらしい

Perlのuseで大文字小文字

例えば、こんなモジュールを作ったとして、

# Parent.pm
package Parent
use strict;
use warnings;

our $NAME = __PACKAGE__;

1;

適当に使う側を書いて、

# test.pl
use strict;
use warnings;
use Parent;

print $Parent::NAME, "\n";

実行すると、

$ perl test.pl
Name "Parent::NAME" used only once: possible typo at test.pl line 6.
Use of uninitialized value $Parent::NAME in print at test.pl line 6.

こんなこと言われちゃいます。

何故でしょう?

答え

大文字小文字が区別されないファイルシステムでは、parent.pmがロードされてしまうから。

調べてませんが、他の言語でも同じことが起きるかもしれません。

以下、参考までに。

  • WindowsのNTFSは大文字小文字を区別しません。
  • MacNFS+では、オプションとして大文字小文字を区別することもできるようですが、通常、大文字小文字を区別しません。*1
  • Linuxext4では、大文字小文字が区別されます。

*1:区別するとAdobe系ソフトがバグるらしい