毎日プログラミング奮闘

日々進化するプログラミングの学習ブログ

Linuxが少し好きになった

Linuxってむずかしい。
自己紹介でも書いたが、私は大学時代にLinuxがわからなすぎて挫折した人間だ。

naotaka-blog.hatenablog.com

でも、ラズパイを触ってみたり、LinuxCentOSを触ることで、少しずつ使えるようになってきた。 そして、この本「Unixという考え方」を読んで、Linuxの理解がさらに進んだ。

UNIXという考え方―その設計思想と哲学

UNIXという考え方―その設計思想と哲学

  • 作者:Mike Gancarz
  • 発売日: 2001/02/01
  • メディア: 単行本

この本はイントロダクションと第1章が肝心。

UNIXの創造者たちは、ある極端なコンセプトから始めた。ユーザーは初めからコンピュータを使えるとみなしたのだ。UNIXは「ユーザーは自分が何をしているかをわかっている」との前提に立っている。(中略)UNIXの設計者たちは「何をしているか分からないのなら、ここにいるべきではない」という不適切きわまりないアプローチを選んだ。

そう。
この文章からわかるように、Unixは玄人向けに設計されている。だから、遊ぶために大学に通っていた僕に、Unixの兄弟みたいなLinuxがわかるはずがなかったのだ。
そして、Unixの9つの定理で成り立っている。(他にも重要度の低い定理が10つある)

  1. スモール・イズ・ビューティフル(小さいものは美しい)
  2. 一つのプログラムには一つのことをうまくやらせる
  3. できるだけ早く試作する
  4. 効率よりも移植性を優先する
  5. 数値データはASCIIフラットファイルに保存する
  6. ソフトウェアを梃子(てこ)として使う
  7. シェルスクリプトによって梃子の効果と移植性を高める
  8. 過度の対話的インターフェースを避ける
  9. すべてのプログラムをフィルタとして設計する

この中の第3章はおすすめである。

すべてのシステムは、若年期から始まり、成熟期を経て、老年期に達して一生を終える。
・ 第一のシステムは追いつめられた人間が作る。
・ 第二のシステムは委員会が設計する。
・ 第三のシステムは第二のシステムで「火傷」した人が作る

この引用した項目を説明している内容が非常にためになった。



話は少し変わるが「スモール・イズ・ビューティフル」や「一つのプログラムには一つのことをうまくやらせる」のようなUnixの設計思想は、Node.jsに受け継がれている。これはO'REILLYのNode.jsデザインパターンに記載されている。

Node.jsデザインパターン 第2版

Node.jsデザインパターン 第2版


最近、UnixLinuxの考え方がわかり、ターミナル操作が苦にならなくなった。

JavaScriptとC++のクイックソート速度比較

速度比較

C++の方が圧勝なはず。。でもどうなんだろう?? 比較してみよう!といった感じ。

実験内容

1000個のランダムな数字に対してクイックソートを行う。それを10回した平均スピードを求める。 それで、1〜4を比較してみる。

  1. JavaScript の array.sort
  2. JavaScriptクイックソート
  3. JavaScriptC++ クイックソート
  4. C++ クイックソート

PCスペック

MacBook Pro(2020春)
f:id:naotaka0608:20200811144339p:plain:w300

実行

$ node index.js

===== array.sort =====
Rap:  289 micro sec
Rap:  264 micro sec
Rap:  269 micro sec
Rap:  271 micro sec
Rap:  423 micro sec
Rap:  283 micro sec
Rap:  181 micro sec
Rap:  180 micro sec
Rap:  179 micro sec
Rap:  177 micro sec
Avg:  283.2 micro sec

===== JavaSctipt Quicksort =====
Rap:  659 micro sec
Rap:  1179 micro sec
Rap:  573 micro sec
Rap:  214 micro sec
Rap:  68 micro sec
Rap:  65 micro sec
Rap:  66 micro sec
Rap:  66 micro sec
Rap:  64 micro sec
Rap:  68 micro sec
Avg:  333.5 micro sec

===== Node -> C++ quicksort =====
Rap:  216 micro sec
Rap:  186 micro sec
Rap:  189 micro sec
Rap:  192 micro sec
Rap:  192 micro sec
Rap:  185 micro sec
Rap:  188 micro sec
Rap:  183 micro sec
Rap:  187 micro sec
Rap:  204 micro sec
Avg:  219.3 micro sec

===== C++ quicksort =====
Rap:  38 micro sec
Rap:  36 micro sec
Rap:  39 micro sec
Rap:  39 micro sec
Rap:  38 micro sec
Rap:  36 micro sec
Rap:  36 micro sec
Rap:  38 micro sec
Rap:  38 micro sec
Rap:  38 micro sec
Avg:  37.6 micro sec

結果

4番目のC++圧勝!
3番目のNode→C++は受け渡しで時間かかってそう。4番目から考えて、受け渡しに180 micro sec くらい!?
2番目のJavaScriptクイックソートは前半遅く、後半が速い。1回目だけであれば、スクリプト言語だから?と言えそうだけどなんでだろう?? 1番目もちょっと遅い感じかな。

今回使ったプログラム

GitHub - naotaka0608/node-cplus-qsort

N-APIを使って、JavaScriptからC++で書かれたクイックソートをよんでみる

N-APIを使って、C++を楽しむ

Nodeを調べているときに、N-APIを使えばJavaScriptからC++が呼べるというもの見つけた。C++好きとしてはどうしてもJavaScriptからC++を呼び出してみたい。そしてできれば、JavaScriptC++の速度比較なんてものをしたい。

アドオンの設定

NodeからC++のアドオンする方法は下記のサイトを参考にした。
N-API を使って Node.js に C++ によるアドオンを実装する最短の道。 - Qiita

配列を呼ぶ方法

配列を呼び出す方法がのってなくて苦労した。
色々調べていると、海外で参考になりそうなサイトを見つけた。

N-API add-on and JS code performance comparison | by Denis Malykhin | Medium

c++ - Node-Addon-Api Pass Array As Function Argument - Stack Overflow



完成プログラム。
GitHub - naotaka0608/node-sort-test

addon.cpp内で配列のデータの受け渡し方法がわからなかった。 わかってしまうと簡単だが、けっこう苦戦してしまった。

#include <napi.h>
#include <iostream>
#include <time.h>
#include "./myLib/sortLib.h"

using namespace Napi;

Napi::Array QuickSortJS( const CallbackInfo& info ) {

    Napi::Env env = info.Env();

    // 引数 1
    Array array_val = info[ 0 ].As<Array>();
    const int max_value = array_val.Length();

    int *array = new int[max_value];
    
    // int配列に移し替え
    for(int i=0; i<max_value; i++){
        Napi::Value v = array_val[i];
        if (v.IsNumber()){
            array[i] = (int)v.As<Napi::Number>();
        }
    }

    // 引数 2 と 3
    int start, end;
    start = info[ 1 ].As<Number>().Int32Value();
    end = info[ 2 ].As<Number>().Int32Value();

    // ソート
    SortLib sortLib;
    sortLib.QuickSort(array, start, end);
    
    // Napi配列に移し替え
    Napi::Array outputArray = Napi::Array::New(env, max_value);
    for (int i=0; i<max_value; i++) {
        outputArray[i] = Napi::Number::New(env, array[i]);
    }

    delete[] array;

    return outputArray;
    
}

Object Init( Env env, Object exports ) {
    exports.Set( String::New( env, "quickSortJS" ), Function::New( env, QuickSortJS ) );
    
    return exports;
}

NODE_API_MODULE( addon, Init )

画像処理の本の今と昔

学生のころに使っていた画像処理の本

僕が学生のころ、10年数年前は画像処理のアルゴリズムが書いてある本がけっこうあったように感じてます。 その中でも「C言語による画像処理入門」と「C言語で学ぶ実践画像処理」には学生時代のころに大変お世話になりました。

C言語で学ぶ実践画像処理」に書いてある「画像のラベリング」はとても懐かしい。 その当時は卒論のためにプログラミングをしていたようなものだったので、プログラムの効率化などはまったく考えてなかった。 今見ると、ちょっと効率悪くない??と思うけど、そんなこともわからなかった。

時間に余裕ができたこともあり、久々に画像処理をやり直してみようと思う。 CやC++が得意だけど、できればRustでやってみたい。

最近の画像処理の本

OpenCVが主流になり、Pythonからライブラリを呼び出す方法の本が多い。 都市部の本屋であれば、画像処理アルゴリズムが書かれた本があるかもしれないけれど、郊外の本屋はほぼ無い。 今はPython機械学習OpenCVの本だらけ。

作られたライブラリを呼び出すのではなくて、アルゴリズムを少し変えてみて、画像の変化を見るのが楽しいのに。。。
と思いながら、本を立ち読みしてます。 プログラムでメモリ破壊していることに気づかず、動作がおかしくなって、1日悩むとかしょっちゅうでした。