2020/06/28

[js]マルチスレッドしたい

JavaScriptはシングルスレッドだったよな、と思っていたのだが、Node.jsではworker_threadsなるものが使えるそうだ。
バックグラウンドで結果を待ち続けつつも表での処理は続けたかったので、2つjsファイルを起動しないといけないのか悩んでいたのだった。


Worker Threads | Node.js v12.18.1 Documentation
https://nodejs.org/docs/latest-v12.x/api/worker_threads.html

私が見たときはNode v14.4.0だったのだが、動かしているのはNode v12.18.1だ。

 

とりあえず、一番上にあったコードを動かしてみよう。
・・・何も起きない。。。
__filenameは実ファイルに置き換えないといけないのかと思ったが、そういうわけでもない。
ログを埋め込んで、isMainThreadで分岐してmain threadと認識しているところまでは分かった。

 

そういえば、module.exportsは外部に提供する場合だったような。。。
今さらだが、module.exports に関数を代入する書き方をした場合、それをrequire()すると関数本体だけが渡されたことになる。
だから、require()した変数に()を付けるだけで実行できる。

 

などと勉強しながらやっていったのだが、たぶんこの例は単独で動かすことはできない。
だって、mainじゃない方の分岐ではrequire()でパースするライブラリを必要としているし。

よし、このサンプルは忘れよう。


次はここだ。

worker_threadsを使ったNode.js マルチスレッドプログラミング - kakts-log
https://kakts-tec.hatenablog.com/entry/2018/12/14/005316

いきなりAPI仕様を見ても分からんので、使い方をある程度見てからにする。
worker.workerDataのサンプルが動いた。

  1. new Worker()でworker thread生成。__filenameは__FILE__みたいなものか。workDataでworkerに値を与えられる。
  2. 起動したworker threadはコンソールログを出してmain threadにスレッドIDをpostMessageする
  3. main threadではEmit Eventで”message”を待ち受けていて、postされたメッセージをコンソールログに出す

main threadでもworkerにpostMessageしているが、これは使っていないようだ。

 

workerDataに関数は指定できるのだろうか?

const {Worker, isMainThread, workerData, parentPort, threadId} = require('worker_threads');

function yoshio(name) {
  console.log(`yoshio=${name}`);
}

if (isMainThread) {
  // mainスレッド
  console.log(`Main Thread!!! isMainThread: ${isMainThread}, threadId: ${threadId}`);

  // 4つ作成する
  for (let i = 0; i < 4; i++) {
    const worker = new Worker(__filename, { workerData: yoshio });
    worker.on('message', (message) => {
      console.log(`[main] message got from worker : ${message}`);
    });

    worker.postMessage("from tokyo")

  }
} else {
  // workerスレッド
  console.log(`[worker] workerData: ${workerData} isMainThread: ${isMainThread}`)
  parentPort.postMessage(`ThreadId: ${threadId}`)
}

ダメだった。

$ node main.js
Main Thread!!! isMainThread: true, threadId: 0
internal/worker.js:194
    this[kPort].postMessage({
                 ^

DOMException [DataCloneError]: function yoshio(name) {
  console.log(`yoshio=${name}`);
} could not be cloned.
    at new Worker (internal/worker.js:194:17)
    ........


classにしたら渡せるのかと思ったのだが、エラーにはならないものの、プロパティしか渡されなかった。JSON.stringify()で見たところ値まで一緒に出てきた、し関数も出てこないし、classが渡されたというよりはコピーしてプロパティだけが残された、ということか。

 

うーん、pthreadみたいにvoid*で大元から渡せると楽なのだけど、同期とか考えると参照渡しはできないということか。。。

試しに、new Worker()の前にインスタンスを作って、スレッド分岐後のmain thread側で書き換えてみたのだが、反対側のthreadには反映されなかった。
アドレス値が表示できればもう少し自信が持てるのだが、まだJavaScript慣れしていないので実装がうまくないだけかもしれん。。。

 

Node.jsのworker_threadsに何を渡すべきか - Qiita
https://qiita.com/ayatty/items/1f5dde995251ac5800ad

共有メモリ方式なのかな?

ただ、私がやりたかったのはメソッドを含めたオブジェクトの共有なのだ。
そういうことは、おそらくできないような気がする。

オブジェクトは1つのスレッドにまとめて、その結果だけをコピーできる形でもらうような設計にする方が無難な気がしてきた。

2020/06/21

[sol]Solidityのこと

なぜ日本語には、「以上」「以下」は対であるのに「未満」の対はないのだろうか・・・。
あったとしても私は聞いたことがないので、あまり普及はしていないだろう。

 

と、本題とはまったく関係ない文章から始まってしまったが、今日はSolidityの学習だ。
細かいところは全部省略する。


Solidity v0.6.10を見る。

Solidity — Solidity 0.6.10 documentation
https://solidity.readthedocs.io/en/v0.6.10/index.html

 

1行目

SPDXを何かしら指定する。

// SPDX-License-Identifier: UNLICENSED

 

2行目

pragmaで対応solcバージョンを指定する。

 

範囲指定

pragma solidity >=0.4.21 <0.7.0;

指定バージョン以上、次バージョン未満(メジャーバージョンやマイナーバージョンの変更がある手前まで?)

pragma solidity ^0.6.11;

 

他にも、構造体を戻り値にしたいpragmaなどある。

 

import

使いたい外部パッケージなど。
残念ながらrequire()はない。
truffle compileなどを使っているとパスの指定はそこまで考えなくて良くなるので助かる。OpenZeppelinとか。

 

本体

これ以降が本体。

 

コメント

//と/* */が使える。
doxygenと同じ感じで、///や/** */もある。
コマンドはdoxygenではなくNatSpecフォーマットというもののようだ。
コンパイル時にうまいことドキュメントにしてくれたりするので、独自でやるよりは従った方が良かろう。


contract, interface, libraryのどれか。
ブロックチェーンに上げられたものは全部見えるので、publicとかprivateとかはない。
変数や関数になるとそういうのが出てくるが、あくまで言語的なアクセスについてだけで、ブロックチェーン的に隠したりとかはチェーンにそういう機能がない限りできない。

 

contractは、他の言語で言うところのclassっぽいもの。
継承もできる。
デプロイがインスタンスを作る作業で、コントラクトアドレスがインスタンスのアドレスと思っておけばいいだろう。

 

abstract contract、というものもあるようだ。
interfaceもあるのだから、どっちかいらないんじゃないかという気もするのだが、作りたいものによっては便利なのかもしれない。

 

libraryはcontractと同じようにデプロイできるのだが、単なる関数の集まりみたいなもので、コンテキストは呼び出し元に依存する。
それだけならよかったのだが、どうもthisが使えるらしいし、呼び出し元のコントラクトのストレージにも触れるようだ。

やらかしてしまいそうなのであまり使いたくないのだが、使いたくなるシーンが出てくるのだろう。
ここら辺は要勉強だ。

2020/06/20

[js]requireとimport

今まで読んでいたJavaScriptのサンプルコードでは、外部モジュール(npmでインストールしたものなど)を使いたいときにはrequire()が使われていた。
なので、C言語で言うところのincludeみたいなものだろうと解釈していた。

 

require()ってどういうパスの解釈をするのだろう、と調べようとしたのだが、なんだかimportというものが出てきた。
時代の流れで変わってしまったとかだろうか?


一番わかりやすいのがここだった。

export / import と exports / require - Qiita
https://qiita.com/kumagaias/items/c8e87bbea496a5351234

なるほど、require()はNode.jsなのか。
だからそれしか見たことが無かったのかもしれない(ブラウザのことを考えていないので)。

Node.js v12.18.1で動かしてみる。

 

 

expo84.js

let Expo = 84;

function ExpoFunc(val) {
    return val + 84;
}

export { Expo, ExpoFunc }

 

expo_use.js

import { Expo, ExpoFunc } from './expo84.js'

console.log(Expo);
console.log(ExpoFunc(10));

$ node expo_use.js
(node:24541) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
/home/ueno/Prog/expo_use.js:1
import { Expo, ExpoFunc } from './expo84.js'
^^^^^^

SyntaxError: Cannot use import statement outside a module
  ...

 

モジュールとわからせないといけない?
あるいは拡張子が.mjsならよい?

 

expo84.mjs

let Expo = 84;

function ExpoFunc(val) {
    return val + 84;
}

export { Expo, ExpoFunc }

 

expo_use.js

import { Expo, ExpoFunc } from './expo84.mjs'

console.log(Expo);
console.log(ExpoFunc(10));

 

あれ、これでもダメ??

 

 

expo84.mjs

let Expo = 84;

function ExpoFunc(val) {
    return val + 84;
}

export { Expo, ExpoFunc }

 

expo_use.mjs

import { Expo, ExpoFunc } from './expo84.mjs'

console.log(Expo);
console.log(ExpoFunc(10));

$ node expo_use.mjs
(node:24577) ExperimentalWarning: The ESM module loader is experimental.
84
94

 

expo84.jsに戻すとそれはそれでエラーになったので、拡張子を変える場合は呼ばれる方も呼ぶ方も.mjsでないとダメとか?

 

require()を使うなら、こういう感じか。

 

expo84.js

let Expo = 84;

function ExpoFunc(val) {
    return val + 84;
}

module.exports = { Expo, ExpoFunc }

 

expo_use.js

const myexpo = require('./expo84.js');

console.log(myexpo.Expo);
console.log(myexpo.ExpoFunc(10));

$ node expo_use.js
84
94

 

うん、もうrequire()でいいや。。。

[vscode]自動でSuggestions候補を出したくない

Visual Studio Code v1.46.1を使ってJavaScriptを書いているのだが、ドット(.)を打ち込むと自動的に候補が出てくるのに困っていた。

出てくれるとありがたい場合もあるのだが、候補一覧が邪魔してコードが見えなくなることもある。
表示するまでの時間を延ばしてみたのだが、ドットだけ打って、変更する前にちょっと動かしてみようとターミナルにフォーカスを移動してごにょごにょコマンドを入力している間に一覧が表示されたりして、あまり精神的によろしくなかったのだ。

 

設定がいろいろあるので、やり方は違うかもしれんが、私の場合はこれが向いていた。

"editor.suggestOnTriggerCharacters": false

トリガになる文字を打ってもSuggestionしなければいいだけだ。Suggestion自体はやってほしいので、それは別のキーに割り当てておけば良い。

 

vscodeは設定が多くて、どれがいいのかわからないのが困るのよねぇ。ぜいたくな悩みだ。

2020/06/13

[js]classがあるのか

JavaScriptのオブジェクトはプロパティが入っているだけだから恐るるに足らず!と思っていたのだが、classなんてものがあることに気付いた。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/class

ECMAScript2015で導入されたらしいので、サポートしていないエンジンだと使えないのだろう。
Node.jsはだいたい対応しているようだから、気にしなくてよいか。
まあ、私がclassを使うかどうかもわからんがね。


class Person {
    living;
    age;
    gender;

    constructor(living, age, gender) {
        this.living = living;
        this.age = age;
        this.gender = gender;
        this.getGender = function() { return this.gender; };
    }
}

var cody = new Person(true, 33, 'male');
console.log(cody);

$ node prop.js
Person { living: true, age: 33, gender: 'male', getGender: [Function] }

 

うーん、これでは違いがよくわからん。。。
GUIの部品とオブジェクト指向は相性がいいような話を聞くので、使いやすいシーンがあるのだろう。


前回のように、コンストラクタを置き換えてみる。

class Person {
    living;
    age;
    gender;

    constructor(living, age, gender) {
        this.living = living;
        this.age = age;
        this.gender = gender;
        this.getGender = function() { return this.gender; };
    }
}

var cody = new Person(true, 33, 'male');
console.log(cody);

cody.constructor = function Yoshio(){};
console.log(cody);

Person.constructor = function(banana) {
    this.banana = banana;
};
var cody2 = new Person('great banana');
console.log(cody2);

$ node prop.js
Person { living: true, age: 33, gender: 'male', getGender: [Function] }
Yoshio {
  living: true,
  age: 33,
  gender: 'male',
  getGender: [Function],
  constructor: [Function: Yoshio]
}
Person {
  living: 'great banana',
  age: undefined,
  gender: undefined,
  getGender: [Function]
}

 

ほう! これは予想外の結果だ。
constructorの置き換えで”Yoshio”になるのは分かるのだが、わからんのはbananaだ。
予想では、bananaというプロパティを追加するのだろうと思っていたのだが、結果としてはlivingが代用されている。というか、bananaのコンストラクタ置き換えができていないように思う。

「オブジェクト」と「インスタンス」で用語を分けるなら、インスタンスのコンストラクタは置き換えられるが、オブジェクトのコンストラクタは変更できないということだろう。

インスタンスになってしまえば、コンストラクタの置き換えもできるし、プロパティ(フィールド?)の追加もできる。
JavaScriptというだけで何でも変更できてしまうという心配をしていたのだが、型になる部分の変更は簡単にはできないということだろう。

[js]コンテナの表示名

前回、こういうコードを書いた。

var Person = function(living, age, gender) {
    'use strict';
    this.living = living;
    this.age = age;
    this.gender = gender;
    this.getGender = function() { return this.gender; };
};

var cody = new Person(true, 33, 'male');
console.log(cody);

var bob = new Object();
bob.gender = 'zombie';
bob.age = '153';
bob.getLiving = function() {
    return this.living;
};
bob.living = false;
console.log(bob);

$ node prop.js
Person { living: true, age: 33, gender: 'male', getGender: [Function] }
{ gender: 'zombie', age: '153', getLiving: [Function], living: false }

 

codyの方は”Person”と表示されるが、bobの方は何も表示されない。
bobは”Object”と表示されてもいいんじゃないだろうか?
あるいは、何かが足りないから表示されないのだろうか。

本では、実行環境によってオブジェクト型の表示が変わるとは書いてあるのだが、何を見て表示しているのかは書いていない。


ありそうなのは、コンストラクタだろう。
cody.constructorとbob.constructorをconsole.log()してみよう。

[Function: Person]
[Function: Object]

Objectの場合は表示しない、というルールかもしれない。

var Person = function(living, age, gender) {
    'use strict';
    this.living = living;
    this.age = age;
    this.gender = gender;
    this.getGender = function() { return this.gender; };
};

var cody = new Person(true, 33, 'male');
console.log(cody);

var bob = new Object();
bob.gender = 'zombie';
bob.age = '153';
bob.getLiving = function() {
    return this.living;
};
bob.living = false;
bob.constructor = cody.constructor;
console.log(bob);

$ node prop.js
Person { living: true, age: 33, gender: 'male', getGender: [Function] }
Person {
  gender: 'zombie',
  age: '153',
  getLiving: [Function],
  living: false,
  constructor: [Function: Person]
}

うむ、予想したとおりだ。

 

var Person = function(living, age, gender) {
    'use strict';
    this.living = living;
    this.age = age;
    this.gender = gender;
    this.getGender = function() { return this.gender; };
};

var cody = new Person(true, 33, 'male');

var bob = new Object();
bob.gender = 'zombie';
bob.age = '153';
bob.getLiving = function() {
    return this.living;
};
bob.living = false;

cody.constructor = function Yoshio(){};
console.log(cody);
console.log(bob);

$ node prop.js
Yoshio {
  living: true,
  age: 33,
  gender: 'male',
  getGender: [Function],
  constructor: [Function: Yoshio]
}
{ gender: 'zombie', age: '153', getLiving: [Function], living: false }

関数を設定すると、関数名がそのまま出力されるようだ。

 

まあ、コンストラクタは最初しか使われないはずだから、どうでもよいのかもしれん。

2020/06/07

[js]オブジェクト

JavaScriptがわからないと困ることが多くなってきた。
golangの勉強もまだまだなのだが、平行してやらないと。

ネットで検索しながら勉強しているとよくわからなくなってきたので、本を買った。

O'Reilly Japan - 開眼! JavaScript
https://www.oreilly.co.jp/books/9784873116211/

さあ、私も開眼できるのだろうか?


こんなことが書いてあった。

オブジェクトはプロパティの集合体を格納するコンテナです。

メソッドも含めてプロパティなのだそうだ。

 

そりゃそうだろう、と思っていたのだが、JavaScriptのオブジェクトはC++やJavaよりも柔軟というか、golangに近いようだ。

時系列的にはgolangの方が後から出た言語なので、逆だろう、といわれそうだが、私が勉強した順だから仕方ない。

 

var Person = function(living, age, gender) {
    'use strict';
    this.living = living;
    this.age = age;
    this.gender = gender;
    this.getGender = function() { return this.gender; };
};

var cody = new Person(true, 33, 'male');
console.log(cody);

var bob = new Object();
bob.living = false;
bob.gender = 'zombie';
bob.age = 153;
console.log(bob);

function print(aaa) {
    'use strict';
    console.log(aaa.age);
}

print(cody);
print(bob);

 

codyはPersonはコンストラクタで作ったインスタンスで、bobはObjectをnewして作ったインスタンスだ。
しかし、関数(オブジェクトに紐付いてなくてもメソッドなのかな?)のprint()で引数としてはどちらでも受け入れるし、出力も期待通りになった。

Javaはすべてのclassはjava.lang.Objectの派生だったと思うが、JavaScriptはそういう継承とか何とかいう概念ではなく、プロパティの名前が一致していれば「そういうプロパティがある」ということを受け入れてくれるのだ。

 

これは、bobのプロパティを設定する順番を変更し、ageを文字列にして、getLiving()というメソッドを追加したのだが、それでも実行時エラーにならない。
print()なんか、演算までしているのに、だ。

var Person = function(living, age, gender) {
    'use strict';
    this.living = living;
    this.age = age;
    this.gender = gender;
    this.getGender = function() { return this.gender; };
};

var cody = new Person(true, 33, 'male');
console.log(cody);

var bob = new Object();
bob.gender = 'zombie';
bob.age = '153';
bob.getLiving = function() {
    return this.living;
};
bob.living = false;
console.log(bob);

function print(aaa) {
    'use strict';
    console.log(aaa.age + 3);
}

print(cody);
print(bob);

$ node prop.js
Person { living: true, age: 33, gender: 'male', getGender: [Function] }
{ gender: 'zombie', age: '153', getLiving: [Function], living: false }
36
1533

codyのageは数字だったので3を足し、bobのageは文字列だったので’3’が末尾に追加された。

 

一番最後にこういうのを追加しても、それでも動く。

cody.age = '99';
print(cody);

993

 

この辺が、C++やJavaのような言語と違うところだろう。
最初に決めた型が絶対ではないのだ。C++で同じことをしようとしたら、void*と型を示す変数を追加するとかになるのか?

 

ともかく、オブジェクトは単なる入れ物だ、ということだ。
そしてこの自由さが私にとってはすごくやりづらいところでもある。慣れるしかないのだが。。。