xargsで並列にコマンドを実行しつつ標準出力・エラーを区別出来るようにする

たまにシェル上での処理を並列実行したくなりますよね?単にバックグラウンドで実行するだけなら&だけでいいんですが、定期的に実行するような時間のかかるスクリプトを複数CPU使って速く終わらせたい場合はとてもあると思います。そういう時に便利なのがxargs(macOSに最初から入っているので良い)。

find . -name *.txt -print0 | xargs -0 -L1 -P4 ./script.sh

こんな感じで自分でfor-loopとか使って頑張らなくても勝手に標準入力から入力内容を読み取ってくれて、入力に応じて並列に処理を進めてくれる。(ちなみにfindの-print0とxargs -0は組み合わせて使うことを意図されていて、入力の分割を改行・空白ごとではなく\0 null文字でしてくれるようになるのでfindで見つけたファイル名に空白が含まれていても処理がおかしくなることがない。) -Pオプションがプロセス数の指定で最大4並列で指定したコマンドを実行できる。ただ、この時にエラーが発生した時にどの入力に対して怒ったのか分からないと困る時がありますよね。スクリプトの中で独自にエラーをログに残す処理を書いたりしても良いけど、既存のコマンドを単に組み合わせているだけの場合はラッパーなどを書くのは面倒臭い。

その場合は、こんな感じでxargsの"-I"オプションとsh -cで別のシェルでコマンドを起動することで標準エラー出力にprefixを付けることができる。

find . -name *.txt -print0 | \
xargs -0 -L1 -P4 -I{} sh -c "./script.sh {} 2>&1 | while read -r line; do echo \"{}:\$line:\"; done"
  1. xargs-Iオプションを使って処理する入力値を置換文字列(?)として定義しておく。そうすると実際に実行するコマンド部分の好きな箇所で入力値が扱えるようになる。(上の例では {} を置換文字列にしておいた)
  2. sh -cで並列化したいコマンドを実行する。コマンドの標準エラーを標準出力にリダイレクトしてパイプで渡せるようにする。
  3. 並列化したコマンドの出力をwhile readで行ごと読み込んでechoで再度出力する。その際に、xargsの置換文字列をprefixとして足せばエラーが発生した入力がなんだったのか区別がつく。whiile readのあたりは何使っても良いので ruby -e 'STDIN.each {|x| puts "{}:#{x}" }' みたいなのでも問題ない。

そんな感じでxcodebuildのimportLocalizationsを実行するfastlaneのpluginの並列化してみた。17言語ぐらいを逐次で実行すると3〜4分ぐらいかかるのが、全部同時に実行すると20秒前後で終わるようになる。ただし言語ファイルごとにこけることがあるのでエラーログが区別出来ないと運用上心許ない。

# Join file paths with null sequence to use "xargs -0" options
# so that 'xargs' can ensure that 'xargs' processes a given filename including even whitespaces
source_paths = params[:source_paths].map { |x| Shellwords.escape(x) }.join('\0')
project = Shellwords.escape(params[:project])
concurrency = Shellwords.escape(params[:concurrency])

# This value is used to pass a variable coming from xargs to the command executed.
xargs_param = "{}"

# xcodebuild command to import localizations
xcodebuild = %(xcodebuild -importLocalizations -project #{project} -localizationPath #{xargs_param})

# In order to distinguish error messages, this script append a filename as perfix to each line of output
error_logger = %(while read -r error; do echo \\"#{xargs_param}: \\$error\\"; done)

# 1. List xliff files that you want to import
# 2. xargs run sub shells that execute xcodebuild in prallel
sh "echo \"#{source_paths}\" | xargs -0 -L1 -P#{concurrency} -I#{xargs_param} sh -c \"#{xcodebuild} 2>&1 | #{error_logger}\""

https://github.com/ainame/fastlane-plugin-localization/blob/9c81565c5e15247e1ce83f382b380de90f9007b3/lib/fastlane/plugin/localization/actions/import_localizations_parallel_action.rb#L26

趣味で書いてるSwift

最近、引き続き趣味でCベースのライブラリのSwiftバインディングを書いている。Swift使ってポインタの気持ちになるのは難しい。

今試しているのが intel/hyperscan というintelが作っているめちゃくちゃ速い正規表現のライブラリで、一部のユースケースに特化してパフォーマンスあげているらしい。最近はGitHubもアクセストークンを検知する処理の中で使っているとか

github.com

こんなことし始めたのもこのページを見てからで、NSRegularExpressionめっちゃ遅いじゃんって思ってなんとなくこのベンチマーク早く出来たら面白そうというところから試してみている。

Swift vs Go - Which programs are faster? | Computer Language Benchmarks Game

とりあえず同期的にパターンとマッチングするコードは書けるようになった。

import Hyperscan

let scanner = Hyperscan()
print("かえるぴょこぴょこみぴょこぴょこ")
print(scanner.scan("かえるぴょこぴょこみぴょこぴょこ", for: "ぴょこ")?.matches)
// => Optional([Hyperscan.Match(from: 0, to: 18), Hyperscan.Match(from: 0, to: 27), Hyperscan.Match(from: 0, to: 39), Hyperscan.Match(from: 0, to: 48)])

print("123456789")
print(scanner.scan("123456789", for: "123")?.matches)
//=> Optional([Hyperscan.Match(from: 0, to: 3)])

print("abcdfabacbabac")
print(scanner.scan("abcdfabacbabac", for: "aba")?.matches)
// => Optional([Hyperscan.Match(from: 0, to: 8), Hyperscan.Match(from: 0, to: 13)])

パフォーマンスの都合上、マッチ開始位置はデフォルトでは保持されないようになっていて、返すためにはオプションを渡す必要があるとのこと。まだ返り値がbytes数換算でのoffsetしかまだ対応していない。とりあえず動く程度なので実用的ではない。streamの入力にも対応できたらカッコ良さそう。

github.com

イギリスで育休取得して子育て(近況)

ainame.hateblo.jp

前回からの近況

  • 12月〜1月は短期の家に住みながら、家を探しをしていたりこちらのオフィスでの仕事が始まった
  • 2/9からようやく新しい家に住めたけど、その家から引けるインターネットが遅すぎて絶望した(色々探したけど固定回線では12Mbpsのプランが最高...海外はインターネット遅いとは承知していたけどここまでとは...)
  • 3/16にブリストルにて子供が産まれて2週間ほどPaternity Leave(有給の育休)を取得し始めた
  • 3/19からインターネット使えるようになったけど遅い(実測で平均2Mbps程度たまに繋がらない)
  • 3/20に日本から送った船便の荷物が大量に届いてダンボール箱をひたすら潰す

出産

当日朝、陣痛が強くなって産まれそう!って状態になったので夫婦一緒に病院まで移動して病院についてから2時間程度で子供が産まれた。めっちゃ安産。 陣痛中に妊婦の腰に押し付けてマッサージに使えるあのテニスボールも全然使うタイミングがなかった。せっかく買ったのに。

イギリスでは、体調が問題なければ出産したら1、2泊後に自宅に帰されるので、出産翌日にベビーカーをおして妻と息子を迎えに行った。 (その代わりに、助産師が数日間家に訪問して色々アドバイスとか体重・血糖値のチェックとかをしてくれる。) 2885gなのでちょっと小さめだけど問題なし。彼は助産師の親が編んでくれたという、毛糸の小さいニット帽子を被らされた。

入院中

産まれた直後から子が親に預けられるので、息子に初めてのミルクあげるのとオムツ交換したのは父親の自分です。 こちらでは母乳育児は勧められてはいるけど、強制ではないし便利な液体ボトルのミルクがあるので、 妻が休んでる間に、産まれた当日に自分がミルクあげた。

オムツも一番最初に交換した時は、まだ緑色(?)の胎便で、しかもオムツ交換中に追加の滑らかな💩をひねり出された。 ここから💩との戦いが始まったのだった。

f:id:ainame:20180403090544j:plain:w450

↑初めてのオムツ交換の時に看護師の人に💩の吹き方を教えてもらっている時の図。

そんな感じ1日目はただただ出産と立会いでお互い疲れて1日が過ぎ、2日目は病院に自分は迎えに行きつつも、 その日は結局検査が色々あって帰宅できたのが夕方5時ぐらいだった。

ミルク

父親なので自分で母乳をあげる事はできないけど、母親も産まれた瞬間にドバドバ母乳がでる訳ではないので、 最初は既成のミルクに頼らざるをえない。しかし、新生児は胃が小さくまた哺乳瓶でミルクを飲むと空気が胃の中に入ってしまって、 飲んだばかりのミルクを吐き戻してしまうことがあるため、ミルクを飲ませた後に背中をぽんぽん叩いてゲップをさせる必要がある。

これが最初全然うまくいかなくてめちゃくちゃ吐き戻されていたのだけど、最近(生後18日)は胃もデカくなってゲップもちゃんと出来るので ここ数日一切吐き戻しをしていないのがとても嬉しい!!ミルクの吐き戻しが発生するとあとでミルクをあげなおす必要が出てくるので、 ただでさえ時間取られるミルクあげを2回もやらなきゃならなくて異常に効率が悪いから、それがなくなるのはとても嬉しい。

オムツ交換💩

生後数日はたまに💩を出してくれていたのだけど、途中から便秘になりそれと共に吐き戻しという形で、お尻からじゃなく口から飲んだミルクを出しまくっていて、しばらく大変だった。 ネットに書いてある色々な方法を試したり助産師に電話してみたりしたけど結局、おしっこが出てるなら2、3日ぐらい放置しても構わないとの事だったので放置したりした。 便秘明けのオムツ替えをちょうど担当する羽目になったけど、凄かった・・・。

家事

妻は色々な情報をもとに、産後1ヶ月は絶対に家事をしない宣言をしていたので一通りの家事も自分がやることになった。 イギリスに住んでてよかったなと思ったのは、でっかい食洗機が家に備え付けられれているので食器洗いのコスト100ぐらいだったものが5ぐらいに減って最高って毎日思っている。 日本に帰っても食洗機絶対に買うと思う。逆に洗濯機は乾燥機が付いてなくて逆に不便。(洗濯機もキッチンの一部として組み込まれている)

料理

船便で日本から送ったものが届くまでは米を鍋で炊いたりしていたけど、海外対応の炊飯器も届いてご飯炊き・保温し放題になってかなり便利。 鍋で炊けなくもないけど、IHのヒーターが結構ピーキーなので火の加減が日本で使ってたIHの調理器よりもちょっと難しかったりして、 炊くごとに硬さにムラがあったり底がちょっと焦げちゃったりしたど、炊飯器は間違いが無いので最高。

妻が油の少なめな日本食食べたいということだったので、クックパッドという便利サービスを活用して、 日本食をなんども作っているうちに味付けのコツを掴んだ。こちらでは、日本の料理酒とかみりんが手に入りづらいので代わりに、 白ワイン(料理酒 => 白ワイン, みりん => 白ワイン + 砂糖)を活用しているのだけど、今まで何となくみりんを使って調理していたのが、 みりんの代わりに砂糖で味付けをすることで、日本食の味付けってこんなに甘みが重要だったのかという事を体感したりした。

まだまだ全然毎日の料理を効率よくって感じでは無いけど、こちらのスーパーでは肉がまぁまぁ安いので大量に作って作り置きっていうのを出来るようになって来た。

出生届

イギリスで産まれたので国籍は取れないけどこちらもちろんイギリスにも出生届は出す必要がある。 しかし日本の国籍とパスポート・ビザが無いと今後不便になってくるので、こちらで作ってもらった出生証明書を日本の渋谷区役所に送った、 今後、日本でもそれが受理されたらパスポートの申請とか色々めんどい手続きが必要になってくる。

日本に郵便送るために追跡の出来るEMSで郵便を送ろうとしたら郵便局のおばちゃんになにそれって言われて俺の拙い英語で説明していたらイライラされてちょっとショックだった。 結果、普通の国際郵便でも追跡できるとのことだったので問題なかったけど、EMSのサイト見たらPost officeで送れるって書いてあったのに。

家族アルバム みてね

前職で作ったアプリで、前職の時は子供どころか結婚すらしてなかったので実際に利用することができなかったのだけど、 ついに子供が生まれたので夫婦・両親家族で活用してみた。毎日何気なく子の写真を撮ってアップロードしているけど、 時差のある日本から深夜4時とかにもおじいちゃんおばあちゃんがチェックしていたりする。何で起きているの?って思ったりするけど、 やはり孫というのはおじいちゃんおばあちゃんにとって、最高のコンテンツということが改めてわかった。

アップロードした写真をアルバムでみながら夫婦で子の成長をしみじみ感じたり、 💩ぶっかけられた事を思い出して笑ったりできているので子育てに貢献している感じがとてもする。

海外からのアクセスでもだいぶ快適に使えるようになっていてすごい!!!(ありがとうございます🙇‍♂️)

明日から仕事へ復帰だけどこれからも育児・仕事両方頑張ります。

追記:

実績解除していくぞ!!!

来年からブリストル(イギリス)で働く

近況報告。2018年の1月2日からついにイギリスで働く。12月18日に日本旅立つ。6月に東京のクックパッド株式会社に入社したが、ビザ(Tier 2 General)取得の都合上、 出向ではなく一度退職してからの転籍という形でイギリスのブリストル(ロンドンではない)にオフィスがあるCookpad Ltd.に入社する。妻も一緒に渡英する。

前回の近況報告からのアップデートは以下。

ビザ申請

Tier 2 General (up to 3 years)のビザ申請を行った。 参考までに超詳細に手順を書いたとしても数年後にはUK側の法律が変わっている可能性があるので、 手順は公式の情報を当たるのが良い。

9月末にIELTSの試験を受験してとりあえずかろうじてビザ申請に必要なScore*1を取ることができたので、そこからネット上でビザの申請をして出てきた書類を印刷して、新橋にあるビザ申請センターで申し込むとフィリピンのマニラに申請書類(のスキャンデータ)とパスポート(?)が送られ自分の場合はちょうど1週間で結果が帰ってきた。ここまでで11月中旬ぐらいの出来事。

移住準備・引っ越し

そこから一気に移住までの計画を立て始めた。ビザの申請が通ると自分が指定した入国期間の間に入国しないといけないのでテキパキしないといけない。 移住のためにとりあえず大量に買い物したり準備したりした。

  • 飛行機のチケット確保
  • 現地で家を見つけるまでの仮住まいを1ヶ月ほど確保
  • 買い物
    • 日本食(醤油とか麹とかみそとか出汁用の昆布とか)
    • (小物用の)変圧器
    • 海外の電圧に対応したIH炊飯器
    • ユニクロヒートテック
    • UKの電源プラグのアダプター
  • 米を実家で取れたやつ60kgほど送ってもらった
  • 各種送別会・挨拶など

もともと移住しようと思っていたので家に家具をあんまり増やさなかったけど、それでも冷蔵庫、洗濯機、机、ソファーなどの最低限の家具などもあったので、メルカリ・アッテ・ジモティで捌きました。hitode909さんのブログ*2を読んで買ったドラム式洗濯機は元値12万(購入価格)ぐらいだったのだけど、2年ほど利用して最終的にジモティで7万程度で売れました。他にもMacbook Pro 13inch(Late 2013)も5万7千円でアッテで売れました。

海外移住用の引っ越し業者はここを使いました。物は多くないのですが合計28万ぐらいかかりました。 (移住にまつわる費用は会社から手当出る)

出産・子育て

来年3月14日(予定日)に子供が産まれる予定で、話し合いの結果でブリストルで出産することに。 理由は

  • どこで産んでも怖いものは怖いし痛いものは痛い(妻)
  • 生まれた直後の赤ちゃんを飛行機に乗せるのは大変
  • 里帰り出産を避けたい

などなど。 イギリスでは約2週間の(法定)父親休暇というのがあるらしいので少なくともそれを取得して子育て・妻のケアを頑張ります。

今後・意気込み

今後、何年ぐらいイギリスにいるかは全く分からない(とりあえずビザは3年分だけど)。人生、辛いことばかりだと生きていくの大変だと思うので、まずは環境に適応するためにイギリスで楽しく生活できるようになることを目指す。

今の仕事はちゃんとやっていこうと思っている。今まで自分でやろうと思ったことをすぐに投げ出したことはそんなに多くはないのでなんとか慣れない環境でも頑張る。

イギリスの美味しい(くない)ご飯の画像も気が向いたら公開して行きます。

*1:Overall Scoreで4以上(5.5だったが自慢できる点数ではない https://www.gov.uk/tier-2-general/knowledge-of-english https://www.gov.uk/government/uploads/system/uploads/attachment_data/file/658919/2017-11-13-Approved_Secure_English_Language_Tests_and_Test_Centres.pdf

*2:今年買った洗濯機 - hitode909の日記 blog.sushi.money/entry/2015/12/09/201645

ISCUON7 予選2日目に参加して予選通過出来ませんでした #isucon

同僚の @kaorimatz と @takanabe_w と計3人で「海南鶏飯」(全員初参加。決起会の時にチキンライスを食べに行ったためそう名付けられた。)としてISCUONに初参加した。 言語はRubyを利用して金曜夜に第6回の予選問題をみんなで通して解いてみるなどをやってみた。

結果としては、いわゆる"Cache-Control: public"を最後までつけられずに304でアイコン画像を配信出来ず、 各サーバーの帯域が足りなくなって負荷レベルをあげられず思うように行かなかった。

"Cache-Control: public"に関しては色々言われているけどハマった側の体験としては、 画像をキャッシュされて配信しないと2段階目以上負荷レベルがあげられず、 他の処理がタイムアウトしてしまうことが多かったため、簡単に出来る改善部分もやりきってこれ以上何すれば良いんだろうか? という状態で詰まってしまったのが少し辛かった。とはいえ、インフラ側を@kaorimatzさんに任せきりになってしまっていて チームとして全力で静的ファイル配信を修正しきれなかったのが敗因だったのかもしれない。

個人としては事前にアプリ内のSQLを集計するスクリプトを準備したり、 当日は、N+1をJoinさせて消したり、DBに入ってる画像を書き出すスクリプトをサクサク書いて、 post '/profile'で新しい画像が投稿されたとこはAPIのなかで直接scpで他のホストに画像を配信するという面白実装して サーバー3台をアプリケーションとして使えるようにしたりというのをやったりして、 普段は味わえない開発体験出来てよかった。

静的ファイル配信極めていきたいなという気持ちになったISUCONだった。 あと参加言語も次回参加するならRuby以外も使えるようになりたいなと思った。