2016年2月3日水曜日

異なるクラスのスレッド間で同期させる

久しぶりの投稿

当初はあるクラスのスレッド間で1秒ごとにシーケンシャル処理を行いたいというものだった。

# a.rb
class A
  @m = Mutex.new

  def get
    self.class.instance_variable_get(:@m).synchronize do
      sleep 1
      puts "#{Time.now} => #{self.class.name}"
    end
  end

end

# do.rb
require_relative './a'
require_relative './b' # Aとはクラス名のみ異なる。

ps = [A, B]
ts = []

5.times do
  ps.each do |prog|
    t = Thread.new do
      prog.new.get
    end

    ts << t
  end
end

ts.each { |t| t.join }

do.rbの実行結果は次のとおり。

$ ruby do.rb 
2016-02-03 18:10:30 +0900 => A
2016-02-03 18:10:30 +0900 => B
2016-02-03 18:10:31 +0900 => B
2016-02-03 18:10:31 +0900 => A
2016-02-03 18:10:32 +0900 => B
2016-02-03 18:10:32 +0900 => A
2016-02-03 18:10:33 +0900 => A
2016-02-03 18:10:33 +0900 => B
2016-02-03 18:10:34 +0900 => B
2016-02-03 18:10:34 +0900 => A

  • Aのスレッド間では1秒ごとにメソッドが実行されている。
  • Bのスレッド間では1秒ごとにメソッドが実行されている。
ただ、この全部のスレッドで1秒ごとに処理を実行したいという変更が入ったため変更。
今回はモジュール変数で対応した。


# synchronizable.rb
module Synchronizable
  @@m = Mutex.new

  def m
    @@m
  end
end

# a2.rb

require_relative './synchronizable'

class A2
  include Synchronizable

  def get
    m.synchronize do
      sleep 1
      puts "#{Time.now} => #{self.class.name}"
    end
  end
end

# do2.rb
require_relative './a2'
require_relative './b2' # A2とはクラス名のみ異なる

ps = [A2, B2]
ts = []

5.times do
  ps.each do |prog|
    t = Thread.new do
      prog.new.get
    end

    ts << t
  end
end

ts.each { |t| t.join }

do2.rbの実行結果

$ ruby do2.rb 
2016-02-03 18:24:44 +0900 => B2
2016-02-03 18:24:45 +0900 => B2
2016-02-03 18:24:46 +0900 => A2
2016-02-03 18:24:47 +0900 => A2
2016-02-03 18:24:48 +0900 => A2
2016-02-03 18:24:49 +0900 => B2
2016-02-03 18:24:50 +0900 => A2
2016-02-03 18:24:51 +0900 => B2
2016-02-03 18:24:52 +0900 => A2
2016-02-03 18:24:53 +0900 => B2

すべてのスレッドで1秒ごとに処理が実行されている。

2015年3月28日土曜日

VALUE DOMAINとS3を組み合わせて任意のサイトへのリダイレクトを行う設定(簡易版)


VALUE DOMAINのDNS設定、S3を組み合わせてリダイレクトさせる
URL転送用レコードを作成する機能がVALUE DOMAINには元々存在する。
しかし、違う方法でやる必要があったのでメモ。

お題


エンドユーザが www.tachibanakikaku.com にアクセスした時、
foobar.example.com へリダイレクトさせる。

S3バケットの作成・設定



  • バケット: www.tachibanakikaku.com を作成
  • Static Website Hosting で Enable website hosting を選択
  • Index Document には "index.html" を入力
  • Endpointをメモしておく



index.htmlの用意



  • バケット内に次の内容でindex.htmlをアップロードする

<html>
<head>
  <meta http-equiv="refresh" content="0; url=http://foobar.example.com/">
</head>
<body></body>
</html>


  • index.htmlのPermissionsでGrantee: Everyoneを作成し、Open/Downloadを許可


DNSを設定



  • www.tachibanakikaku.com. IN CNAME <メモしておいたEndpoint>



以上

2014年12月8日月曜日

EC2インスタンスのAMIバックアップを取るスクリプト

Rubyで一瞬。

留意事項

  • 認証情報は別途用意する (e.g. ~/.aws/config)。
  • create_imageはAMI作成リクエストを送り直ぐに戻るという想像の下に書いてる。

2014年11月12日水曜日

DPについての講義を受けた記録(前編)

恥ずかしながら未だにDP(動的計画法)に慣れてないのでどうしたものかなと思っていたら「DPなら俺に任せろ。俺はDPの気持ちが分かる」という方が居られたのでそれならと知人と共に簡単な講義をお願いした。「ちょっと張り切って作ってみた」と聞いていたので少しビビりながらも当日に臨んだのでその記録。この内容は入門レベルなので読む必要ない人の方が多いはず。


導入


DPとはなんぞや


Wikipediaには以下の2つの条件を満たすものと書いてある。
  • 分割統治法
  • メモ化
しかし、講義内ではもう少し厳密さを入れたかったのか、ボトムアップに解いていく点も説明に含められていた。まとめると講義では、「部分問題をボトムアップに解いていく」、同じ計算を二度実行しない」の二点が何度も繰り返された。

その後、フィボナッチ数列を例に説明が為された。


フィボナッチをDPで解く例

演習1(ロッド切り出し問題)


ロッド切り出し問題を使った演習。漸化式を見つけると言う分かりきった分かりにくいものだけではなく、部分最適構造性を見つけるということで含まれていたSchemeの例がわかりやすかった。

長さが5の時は、5, (4, 1), (3, 2)の3パターンだが、1から順に入力値までの最適解を求めながらループさせることになる。

コード例

演習2(LCS)


定番のLCSを使った演習。この漸化式見つけられるならそもそも困らないだろと皆がツッコみたいところである。仮定が大事という言葉にうまく丸め込まれた感は否めない。

仮定→漸化式→プログラム、という風に落としこんでいく感じは掴めた(気がする)。

コード例

所感


こういう機会を設けることに意味はあるが、仕事ではあまり使わない現実が悲しい。
久しぶりに書いたけど、Blogger使いづらい。

DP講義(後編)は11/30開催予定

2014年5月15日木曜日

curlを使ってJSONファイルをPOST

偶に必要な時にパッと出てこないので自分用メモ。 

# test.jsonを用意

WikipediaにあるJSONを一部抜き出した次のJSONをサンプルファイルとして使用する。

{
    "firstName": "John",
    "lastName": "Smith",
    "age": 25,
    "address": {
        "state": "NY"
    },
    "phoneNumbers": [
        {
            "type": "home",
            "number": "212 555-1234"
        }
    ]
}

# curlを実行

$ curl -X POST http://localhost:3000 -H 'Content-Type: application/json' -d @test.json

# 受信側がRailsアプリの場合

パラメータとしてJSONは次のように解釈されている。

[1] pry(#<DashboardController>)> params
=> {"firstName"=>"John",
 "lastName"=>"Smith",
 "age"=>25,
 "address"=>{"state"=>"NY"},
 "phoneNumbers"=>[{"type"=>"home", "number"=>"212 555-1234"}],
 "controller"=>"dashboard",
 "action"=>"index",
(余分なものは省略)

コード内では実際に次のようにJSONファイルの中身を取得できる。

[2] pry(#<DashboardController>)> params[:firstName]

=> "John"

これでまた忘れても大丈夫。

2014年1月19日日曜日

Ancestry

親子構造を格納するモデルを用意しようとしてたら、AncestryというGemを見つけた

準備

適当にrailsプロジェクトを作成し、Gemfileにgem 'ancestry'を記述しbundle install


scaffoldを作る

$ rails  g scaffold tenant name:string


Tenantモデルを編集

# app/models/tenant.rb
class Tenant < ActiveRecord::Base
  attr_accessible :name, :parent_id
  attr_accessible :name # 2014/1/21 parent_idは不要でした
  has_ancestry
end


フォーム編集用ビューを編集

# app/views/tenants/_form.html.erb
<div class="field">
  <%= f.label :parent %><br />
  <%= f.select :parent_id, options_from_collection_for_select(Tenant.all, :id, :name) %>
</div>


Tenantモデルへancestryカラムを追加してマイグレーション

# rails g migration add_ancestry_to_tenants ancestry:string
class AddAncestryToTenants < ActiveRecord::Migration
  def change
    add_column :tenants, :ancestry, :string, after: :id
    add_index :tenants, :ancestry
  end
end


indexビューを編集(抜粋)

# app/views/tenants/index.html.erb
    <td><%= tenant.parent ? tenant.parent.name : nil %></td>
    <td><%= tenant.ancestors.map &:name %></td>
    <td><%= tenant.children.map &:name %></td>
    <td><%= tenant.descendants.map &:name %></td>

この状態でモデルの作成を繰り返すと、indexの表示はたとえば次のようになる

この時、tenantsテーブルの中身は次のようになる







2014年1月1日水曜日

Ansible導入(前編)

2013年からの宿題なのか2014年のお年玉なのか不明だが、確定申告用の領収書類を持ち帰るのを忘れたので大晦日に手持ち無沙汰になっていたのでやってた。後編あるかは不明

Ansibleを使ってできること

  • サーバの構成管理。Chefと同じ目的で使うものという認識
  • 設定として記述したパッケージ・ソフトウェアを簡単に導入できる
  • 冪等性を保ちながらサーバの構築を繰り返し行うことができる(使い方によっては当然冪等性を損なうこともできるけど)

インストール

AnsibleWorksのサイトにあるので参照。たとえば次の方法がある
  • GitHubレポジトリからcloneしてインストール
  • pipインストール
  • yum, apt

ローカルMacにpipが既に入っていたので、pipインストール
$ pip install paramiko PyYAML jinja2 httplib2 
$ sudo pip install ansible

Ansibleで管理対象となるホスト設定を作成

# /etc/ansible/hosts
[experiments]
dev ansible_ssh_port=<ssh port> ansible_ssh_host=<your hostname> ansible_ssh_user=<ssh user>
  • experimentsはAnsible管理のホストをグルーピングしてる
  • devはサーバのニックネーム

Ansibleの動作設定を作成

以降のコマンド実行の際にControlPathが長過ぎて怒られるのを予防。デフォルトは control_path=%(directory)s/ansible-ssh-%%h-%%p-%%r らしいがこれだと長過ぎるみたい。
# /etc/ansible/ansible.cfg
[ssh_connection]
control_path=/tmp/ansible-ssh-%%h-%%p-%%r

テスト

$ /usr/local/share/python/ansible all -m ping
dev | success >> {
    "changed": false,
    "ping": "pong"
}

OKそう。さらにテストしてみる
$ /usr/local/share/python/ansible all -a "/bin/echo hello"
dev | success | rc=0 >>
hello

OKですな

幾つかコマンドサンプル

$ /usr/local/share/python/ansible dev -m copy -a "src=/etc/hosts dest=/tmp/hosts"
#=> ローカルの/etc/hostsをdevの/tmp/へコピー

$ /usr/local/share/python/ansible dev -a "/sbin/reboot" —sudo
#=> devを再起動
$ /usr/local/share/python/ansible -m yum -a 'name=mysql-server state=installed’ dev --sudo#=> devでmysql-serverをyumインストール

しかし、いちいちコマンド打つの面倒くさい。そのため、実行する処理(task)をまとめて記述したもの(Playbook)を使う。

# /etc/ansible/builds_server.yml 
- hosts: experiments
  remote_user: ec2-user
  sudo: no
  tasks:
    - name: test connection
      ping:
    - include: tasks/begins_pkg.yml

# /etc/ansible/tasks/begins_pkg.yml
- name: ensure all packages are at the latest version
  yum: name=* state=latest
  sudo: yes
- name: ensure git is installed
  yum: name=git state=latest
  sudo: yes
- name: ensure apache is running
  service: name=httpd state=started
  sudo: yes

上記を用意した上で、次のコマンドを実行する
$ /usr/local/share/python/ansible-playbook /etc/ansible/builds_server.yml

PLAY [experiments] ************************************************************
GATHERING FACTS ***************************************************************
ok: [dev]
TASK: [test connection] *******************************************************
ok: [dev]
TASK: [ensure all packages are at the latest version] *************************
ok: [dev]
TASK: [ensure git is installed] ***********************************************
ok: [dev]
TASK: [ensure apache is running] **********************************************
ok: [dev]
PLAY RECAP ********************************************************************
dev                        : ok=5    changed=0    unreachable=0    failed=0   

こんな感じで実行結果が出力される。言うまでもないが、

builds_server.ymlで次を記述

  • pingテスト
  • begins_pkg.ymlをインクルード

begins_pkg.ymlで次を記述

  • yum -y update
  • 最新のgitパッケージをyumインストール
  • apacheを起動する(パッケージが無ければインストール)

後編では次のものをする予定
  • EC2イメージからのインスタンスローンチ(Elastic IP貼り付け等も併せて)
  • rbenvベースのrubyインストール