Ractorに入門してみた - Consumers/Producer はこんな感じ?編 -
以下での背景と失敗を踏まえて、元々やりたいことを書いてみた、という内容の記事になります。
やりたい事
- ある処理をするためのデータが多数ある
- それを並列に処理したい。
- 並列数は固定でOK。
- 結果は随時処理したいが、処理つの都合で1カ所でやりたい
みたいな感じです。
の Worker pool
のサンプルだと
(1..N).each{|i| pipe << i }
で、全てのデータを渡してから、最後に結果をごそっと受け取るという感じで微妙にニーズと一致しませんでした。(結果を随時受け取っていきたい)
実装
そこで、実際のデータとか実処理の内容はのぞいて、並列処理部分はこんな感じ?というのを書いてみました。
def main() # 同時実行数 c = 2 producer = Ractor.new Ractor.current, c do |parent, c| puts "start producer" get_data.each do |d| Ractor.yield Ractor.make_shareable(d, copy: true) # sleep 1 end # consumer に終了通知 c.times do Ractor.yield :term end parent.send :producer_finished end consumers = (1..c).map do |i| Ractor.new producer, i do |producer, i| puts "start consumer #{i}" loop do d = producer.take break if d == :term puts "consumer_#{i}: #{d['id']}" Ractor.yield d['value'] end # main Ractor への終了報告 Ractor.yield :consumer_finished end end # consumer からの結果受け取り&終了待ち until consumers.empty? r, obj = Ractor.select(*consumers) if obj == :consumer_finished consumers.delete r next end puts "message: #{obj}" end puts "wait producer" Ractor.receive end def get_data [ { 'id' => 1, 'value' => 'aaa'}, { 'id' => 2, 'value' => 'bbb'}, { 'id' => 3, 'value' => 'ccc'}, { 'id' => 4, 'value' => 'ddd'}, ] end main
一応、これで期待通りっぽく動いているのだけど、果たして。。。
詳しい人に教えて欲しい〜。
Ractorに入門してみた - 基本的なところでハマった編 -
背景
ruby で書き始めたちょっとしたツールで、処理する対象量の都合で並列実行したいな、となり、できればやはり複数 CPU 使いたいなということで、Ruby って Process 以外で今って何かできるんだっけと見たら Ractor というのがあるんですね。
Ractor 自体は
などなど見てもらうのが良いと思います。なんせ、まだ私はわからないことだらけなので。
で experimental ということですが、作ろとしているツールは1回ぽっきり的なので、それなら勉強がてら(最近この手のもので新しいことを使う機会が少ないこともあり)使ってみようと思い手を付けてみました。
この記事は、やってみて、適当な理解なせいでしばらくハマった内容を書いたものです。 ちゃんと考えればわかるでしょ、的な自戒な意味を込めた記事。
なお、rubyのバージョンは以下。
$ ruby --version ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) [x86_64-darwin19]
間違い実装
Consumers - Producer 的な感じなものを実装したくて、プロタイピング的になんとなくで書いてみました。(dame.rb
とします)
def main producer = Ractor.new do get_data.each do |d| Ractor.yield Ractor.make_shareable(d, copy: true) end Ractor.yield :term end consumer = Ractor.new producer do |producer| loop do d = producer.take break if d == :term puts "consumer: #{d['value']}" end end # producer 完了待ち producer.take # consumer 完了待ち consumer.take end def get_data [ { 'id' => 1, 'value' => 'aaa'}, { 'id' => 2, 'value' => 'bbb'}, { 'id' => 3, 'value' => 'ccc'}, { 'id' => 4, 'value' => 'ddd'}, ] end main
- producer からデータ流して、
- consumer で受け取って何か処理
- 後は終了待ち
みたいなやつです。
これ実行すると
$ ruby dame.rb <internal:ractor>:267: warning: Ractor is experimental, and the behavior may change in future versions of Ruby! Also there are many implementation issues. consumer: bbb consumer: ccc consumer: ddd
みたいな感じで、一個データが consumer に渡っていなんですよ。 これにしばらく悩みました。。。
原因は
# producer 完了待ち
producer.take
これ。
当然ですよね。。。
producer.take
するってことは producer
が Ractor.yield
したやつを受け取るので、ここに1つ producer
から流されたデータが渡ってきていた、というだけ。
終了待ちは take
だからという適当な理解で書いてしまった、というオチです。
動くようにしたもの
動くようにするには、この実装だと最後の待ちの順番を入れ替えるだけ。
# consumer 完了待ち consumer.take # producer 完了待ち producer.take
これだと期待通り。
$ ruby ok.rb <internal:ractor>:267: warning: Ractor is experimental, and the behavior may change in future versions of Ruby! Also there are many implementation issues. consumer: aaa consumer: bbb consumer: ccc consumer: ddd
さて、動いていはいるけど、これで本当に良いのか全く自信なし。
:term
みたいなメッセージ投げるのが正しいのだろうか、というのも。
make_shareable
のところはこの記事的なところだと copy: true
必要はないけど、今後予定のことを考えてそうしてはいます。
まだまだ理解に乏しいけど、実装しながら学んでいくことにします!!
(初めから〇〇言語で書けば、というのはあるが...それは置いとく)
iOSDC Japan 2021のコアスタッフやってきました
もうブログはほぼ放棄ぎみなのですが、iOSDC Japan 2021が終わって書く気分になったので書きます。
感謝
今年も大成功にiOSDCが終わったと思います。
スポンサー、スピーカー、参加者、スタッフ(4Sというワードが爆誕してましたね)の皆さまのおかけです。
とても楽しい 2.5 Days でした!!
参加形態
今年もコアスタッフとして参加させていただきました。
スタッフ自体は1回目からさせていただいており、もはや私にとっては一年で一番大事なタスクになっていますね。
普段の通常の仕事よりは完全に優先事項。内緒です。。。
事前の担当
今年は、スピーカー、サポーター向けのノベルティの1つタンブラーを担当しました。
スタッフの Slack でノベルティ案の会話があったときに、ポロッと、「タンブラーとか?」みたいな発言をしたのがきっかけでした。
デザインはデザイナーの方にしていただきましたが、ベースとするタンブラーのサンプル集めから、最終発注までは2か月くらいかかった力作です!! iOSDC Japan 2021のロゴが、タンブラーと蓋にレーザー彫刻で刻印されています。
自分でも大満足な仕上がりになりました。
是非、スピーカー、サポーターの皆さまに長くご愛用いただければ嬉しいです。
おそらく毎年つくるような定番系のノベルティではないので、今後数年は作られないような気がしますし。
当時の担当
当日はリモートからの参加で、Ask the Speaker の方を担当させていただきました。
拙い司会となりましたが、スピーカー、参加者の皆様のおかげもあり、なんとか無事に終えることができたと思います。
ありがとうございました!
来年にむけて
この2年はオンラインでの開催を通じて、以前から参加いただいている方にはオンラインの良さを認識しつつ、オフライン開催の懐かしさも感じ始めたころではないでしょうか?
iOSDCの良いとこの1つは、常にチャレンジをしているカンファレンスだと思っています。
来年はオフライン開催も見えてくる気配もあるので、きっとオン・オフをうまくミックスしたカンファレンスへのチャレンジとなるのではと思っています(実行委員長次第ではある)。
そして、自分もまたそこになにか貢献したい気持ちはあります。
しかし、オン・オフのミックスとなるとスタッフとしてやることは今まで以上に多いと思うので、是非来年は4Sの1つスタッフをしてみようかな、と少しでも思ったあなた!、是非時期がきましたらスタッフへの参加をお願いします!!!
それでは、また来年 iOSDC という同窓会でお会いしましょう!!!
PHPerKaigi 2020 にスピーカー&当日スタッフで参加してきた
PHPerKaigi 2020にスピーカー兼当日スタッフで参加してきました、エントリーです。
スピーカー
二日目に、PHPシステムをコンテナで動かすための取り組みのすべて by きくもと | トーク | PHPerKaigi 2020 #phperkaigi - fortee.jp として30分枠で話してきました。
資料は↓です。
地味なネタだけに通ると思っていませんでしたが、久しぶりに外で話す機会が持てたことに感謝です。
また聞きにきていただいたかたにも感謝です。ありがとうございました。
何か新しい技術とかはないのですけど、実際にやったことであるので、何かの参考になれば幸いです。
やはり話すのは楽しいですね。また良いネタができたときには話したいです。
当日スタッフ
また、今年もですが、当日スタッフでの参加でした。で、例年通り受付してました。
今年は幸い人が集中することもなく、また慣れている参加者もそれなりにいるのか、受付はほぼスムーズに流れていたように思います。
が、今年の最大のポイントはやはり、これですよ、これ
トレカ!
全員にあったわけではないのですがそれでも物量がすごくて、スマートにお渡しできず、ちょっとバタバタしながらのお渡しになってしまったかなぁと思っており、また次回があるなら良い方法を考えてリベンジしたいところです。
お渡しする時の皆さんのリアクションがよくて、受付的にも楽しかったです。
皆さん、ご来場ありがとうございました!
最後に
毎年こうやっていろんな人と交流できるPHPerKaigiに感謝です。また、来年もなんらかの形でかかわっていきたいなぁという気持ちになった 2020 でした。
ありがとうござました!!!
Dygma Raiseがやってきた
7月に申し込んだキーボード Dygma Raise
がついに届きました!
ついにDygmaがやってきた!まずは開封の儀。これで年末年始は楽しめるぞ。 #dygma #dygmaraise pic.twitter.com/RqLd5rfIsz
— kikumoto (@takakiku) 2019年12月28日
申し込んだ時はまだ絶賛開発中だったので、夏の終わりにくれば良いかなと思ってましたが、結局ほぼ半年待った形に。 まぁ、待つことは覚悟してたので、そこはあんまり気にはしてない。
そもそもなぜ Dygma Raise を買ったかですが
- 分割キーボードにしたかった
- Mistel Barocco を持っている人のをみて、1体にもできるのは何となく良さそうだった
- 親指部分に機能を集中させたかった
という感じで調べてたら Dygma Raise を見つけて、これだ!と思いポチりました。
繋いだ状態はこんな感じ(まだまだこれから整えていく)
ファーストインプレッション
キースイッチは Kailh Speed Silver というやつにしました。
まぁ、特に嫌いという感じではなかった打感なので、これで良かったかな。
Macのキーボードに慣れすぎていたから、キーキャップが発する音(と言えばいいのかな)がまぁまぁするなぁという感じ。
親指部分に、Returnとかバックスペースを使えるのはやはり快適。(あくまで個人的感想ですw)
パームパッドもついてくるのだけど、これは私は使わないかなぁ。
本体については基本大満足ですね。本当は、パームレストが取り外せるともっと最高なんだけど。(なお、一体型というのは理解して買っています)
一方問題なのはキーの設定をするソフトウェア。
Bazecor というアプリをダウンロードして使うのだけど、まだまだ不安定な感じですね。
もっとも、不安定なのはソフトなのかキーボード側のファームなのかは定かではないですが。
レイヤーを任意に一発で切り替えたいのだけど、現状は1つのキーに特定のレイヤーの変更を割当る感じになってしまう。
実質2、3レイヤーしか使わないから、レイヤーのために2つのキーを割り当てる程度でまだ棲むけど。
このあたりは、ソフトウエアのアップデートに期待したい。
それにまだまだよく落ちる。。。
ソフトウェアが落ちても別にキーボードそのものはちゃんと動くから、まぁ早く安定版を作ってくれ、という感じ。
キーの設定をテキストでエキスポート、インポートできるのは良いですね。git 管理することにしました。
まだまだ年末・年始休暇は始まったばかりなので、まずはキー設定を自分好みにしていくぞ!!
ファイルが作成されたら自動追尾するfluent-agent-chimeraを作りました
特定のディレクトリ配下に、任意のタイミングでディレクトリが新規作成されて、その配下にログが出力されているような状況下で、そのログをin_tailで取り込みたいという必要性から、fluent-agent-chimera
を作りました。
目次
例えば というディレクトリ、ファイルがあるとします。 これに対して、設定ファイルとして以下のようなものを用意します。 この設定でfluent-agent-chimeraを起動すると、まず のファイルが監視対象となり、ログが出力されると指定のfluentサーバにログがforwardされます。 ここで というファイルが作成されると、dir1/hoge_20180202.log は監視対象からはずれ、dir1/hoge_20180203.log が監視対象となります。 さらに が作成されれば、このファイルも新たに監視対象となります。 このように、監視対象のディレクトリと、正規表現にマッチするファイル(ただし、ファイル名に日付を含むファイル)を新規に作成されるものも含めて自動追尾して、fluentサーバにログをforwardしてくれるのが、fluent-agent-chimeraです。 まぁ、アプリとかバッチのログ出力をちゃんと最初から設計して、普通にfluentやfluent-agent-hydraなどで追えるようにしおけばこんなものは不要なのですが、いろいろ事情もあるわけで(つらい)、こんな GitHubのリポジトリにも書いていますが、fluent-agent-chimeraは、@fujiwara さんの です。基本的な構成は同じで、inotifyでの処理部分を作り込みつつ、in_forwardを削ったり、ファイルの中身を処理するところ削ったりしています。 fluent-agent-chimeraは、基本的に新規作成ファイルの検知がメインで、あとはなるべくローカルのfluentに処理を移譲する、という想定でいます。 あとは、fluentのclientとして、@lestrrat さんの に変更しまいた。fluent-agent-hydraを大きく書き換えているので、fluentのclient部分をfluent-agent-hydraに組み込まれているfluent clientに依存させると、それに追随するのも手間かなと思ったのと、単にいじってみたかったので、変えました。そのおかげで、unix domain socketでfluentサーバと通信も可能です。 今回、初めてGoのソースを公開するってのをしたのですが、一連の公開の手順については、@songmu さんの を多いに参考にさせてもらいました。 goxz 含めて、gobump, ghr, ghch などが見事に連携されていて、このやり方が標準になれば良いのでは、と個人的には思ったほどです。多分、今後もこれにならう感じになりそうです。 個人的には、やっぱりGoは肌にあっているなぁという感じです。もっとGoを書いていきたい。 で、もし感想とかありましたら、@takakiku までいただけると嬉しいかもです。どういうものか
/path/to/batchdir
- dir1
- hoge_20180201.log
- hoge_20180202.log
- xxxx_20180201
- yyyy.log
- dir2
- hoge_20180201.log
[Server]
Network = "tcp"
Address = "127.0.0.1:24224"
[[Logs]]
Tag = "batch"
Basedir = "/path/to/batchdir"
Recursive = true
TargetFileRegexp = "^.+/batchdir/.*(\\d{8})(?:.*\\.log)?$"
FileTimeFormat = "20060102"
/path/to/batchdir
- dir1
- hoge_20180202.log
- xxxx_20180201
- dir2
- hoge_20180201.log
/path/to/batchdir/dir1/hoge_20180203.log
/path/to/batchdir/dir3/hoge_20180202.log
闇のようなツールを生み出しました。実装について
そのほか
最後に
Nginx+SiteGuard LiteのRPM作成Docker - ngx_mruby を添えて -
さくらインターネットの環境でSiteGuard Liteが無償で使えますが、特に今年の6月にはNginx版も提供されるようになっていますね。
それまではApacheのみの対応であったので、Nginxを使っている身としてはちょっと縁がないかなぁと思っていたわけですが、Nginxが出たので利用し始めています。
ただ、仕方ないのですが、Nginxをソースからビルドしてインストールする、という手順となるのでそこが複数台のサーバにインストールするときに面倒だったり、一応バージョン管理もしたいので、イマイチでした。
なので、CentOS7限定(自分が必要だったので)ですが、SiteGuard Lite付きNginx RPMをビルドするためのDockerfileを作ったので公開します。RPM作成となるベースのNginxは、CentOS7向けに公開されているSRPMを使っています。
ついでに、ngx_mrubyも必要であったので ngx_mruby 付きです。公開リポジトリには、ngx_mruby なしも公開しています。
ngx_mruby あり github.com
ngx_mruby なし(同一リポジトリの別ブランチ) https://github.com/kikumoto/nginx-siteguard_lite-rpm/tree/without_nxg_mruby
上記リポジトリのREADMEの通りですが、そもそもさくらインターネットの環境でSiteGuard Liteを利用できる条件を満たしていることが前提です。
その上でリポジトリをcloneして
make
すれば build ディレクトリ配下にRPMが作成されます。
このRPMを使えば、SiteGuard Lite公式のドキュメントにてNginxをビルドする箇所を、RPMインストールに読み替えればOKです。
誰かの参考になれば幸いです。