---
# System prepended metadata

title: '今週何知った？ week:14'

---


# 今週何知った？ week:14

## 各自発表

> [name=ken3ypa]

## 僕もObservableについて調べてみた

### 1: 「観察」よりも「通知」

Observerは能動的に観察するのではなく、Subjectから通知されるのを待っている。
そのため、Pub-Sub（Publish - Subsriribe）の表現の方がより適切

<img width="1339" alt="image.png (37.1 kB)" src="https://img.esa.io/uploads/production/attachments/9475/2022/04/16/39171/70f1a2ab-8c98-4406-a947-d8c46b622065.png">

### 2: 1対多の構成
- Subject(1)-<Observer(多)の関係になる
- これはMVCにおけるMが1、Vが多の関係と同じ

### 3: ARにかつて存在していた Observable の仕組み
https://github.com/rails/rails-observers

### 4: RubyのObservable実装

```ruby
module Observable
  # {
  #   <LowPriceNotifier:0x000000011e97ebf8 @limit=235000>=>:update,
  #   <HighPriceNotifier:0x000000011e97e8b0 @limit=255000>=>:update
  # }
  def add_observer(observer, func = :update)
    @observer_peers = {} unless defined? @observer_peers
    unless observer.respond_to? func
      raise NoMethodError, "observer does not respond to `#{func}'"
    end
    @observer_peers[observer] = func
  end

  def delete_observer(observer)
    @observer_peers.delete observer if defined? @observer_peers
  end

  def delete_observers
    @observer_peers.clear if defined? @observer_peers
  end

  def count_observers
    if defined? @observer_peers
      @observer_peers.size
    else
      0
    end
  end

  def changed(state = true)
    @observer_state = state
  end

  def changed?
    if defined? @observer_state and @observer_state
      true
    else
      false
    end
  end

  def notify_observers(*arg)
    if defined? @observer_state and @observer_state
      if defined? @observer_peers
        @observer_peers.each do |k, v|
          k.send v, *arg
        end
      end
      @observer_state = false
    end
  end
end

class Publisher
  include Observable

  def run
    loop do
      price = Price.fetch
      changed # notify observers
      notify_observers(Time.now, price)
      sleep 1
    end
  end
end

class Price
  def self.fetch
    rand(230_000..260_000)
  end
end

class Subscriber
  def initialize(publisher, limit)
    @limit = limit
    publisher.add_observer(self)
  end
end

class LowPriceSubscriber < Subscriber
  def update(time, price)
    # callback for observer
    if price < @limit
      print "#{time.to_s}: 購読者Aが#{price}円で購入しました！（設定価格 #{@limit}円）\n"
    end
  end
end

class HighPriceSubscriber < Subscriber
  def update(time, price)
    # callback for observer
    if price > @limit
      print "#{time.to_s}: 購読者Bが#{price}円で購入しました！（設定価格 #{@limit}円）\n"
    end
  end
end

publisher = Publisher.new
LowPriceSubscriber.new(publisher, 235_000)
HighPriceSubscriber.new(publisher, 255_000)
publisher.run
```

> [name=makicamel]

## マルチプロセス、マルチスレッド

- `cluster` モジュール  
マルチプロセス化の機能を提供する
- `worker_threads` モジュール  
Node.jx v10 以降、コア API として提供されている。マルチスレッドプログラミングを可能にする

![](https://i.imgur.com/AWw3oua.jpg)
ー [ハンズオン Node.js](https://www.oreilly.co.jp/books/9784873119236/) p.148

### マルチスレッドとマルチプロセスの向き不向き

- マルチスレッド
  - スレッド間通信：スレッド間でメモリ空間などのリソースを共有している
  - プロセス間の通信が頻繁・メッセージが大きいケースに向いている
    - e.g. フィボナッチ数の計算
- マルチプロセス
  - プロセス間通信：IPC (プロセス間通信) を通じて通信する
  - 各プロセスが独立して動作し、プロセス間で通信を必要としないケースに向いている
    - e.g. [Web アプリケーションの並列化](https://github.com/makicamel/til/blob/d101769/books/hands_on_nodejs/part4/ipc/multi-process.js)

### `cluster` モジュール
マルチプロセス化の機能を提供するモジュール
- 以下のような複数ポートの管理
  - 通常ひとつのポートに同時にアクセスできるプロセスはひとつだけ
  - `cluster.fork()` でフォークされたサブプロセス同士は IPC を通じてポートを共有できる
  - ref https://github.com/makicamel/til/blob/d101769/books/hands_on_nodejs/part4/ipc/
- ロードバランサ：子プロセスにリクエストを分散させる
  - スケジューリングポリシー
    - ラウンドロビンポリシー `cluster.SHED_RR`
      - Linux・OSX でデフォルトで有効
    - OS に任せる `cluster.SCHED_NONE`
      - Windows でデフォルトで有効

ref [Node.jsのClusterをセットアップして、処理を並列化・高速化する | POSTD](https://postd.cc/setting-up-a-node-js-cluster/)

内部的には [`child_process`](https://nodejs.org/api/child_process.html) モジュールを利用している

```javascript
// fork メソッドの引数にサブプロセスで実行したいファイルを指定する
const child = child_process.fork('./ipc/web-app')
child.send(3000)
```


## メモ欄
