私が歌川です

@utgwkk が書いている

NFに合わせてエルラに人間が集結した.最終的に30人ぐらい来て,なんとか全員座れた. 店にいる途中で記憶がなくなっており,気がつくと家のベッドにコアダンプしてたので,泣きながら処理した. トイレでコアダンプする習慣がないが帰宅することはできるので,次はトイレでコアダンプするようにすると完璧.

記憶がないとき何をやっていたのか不明で,OBの方の支払い分の1万円がズボンのポケットに入っているということもある. デレステの話をしていたところが最後のセーブポイント

どんどん二日酔い解消グッズとコアダンプ処理の知見が集結していく.まだ頭が痛い.

靴を買った

今まで履いてたスニーカーに穴が空きつつあり,外出すると足がめちゃくちゃ冷えて困っていたので,思いきって厚めの靴を買った. 前の靴もアマゾンで買ったので同じようにアマゾンで調べて購入し,今日届いた.

防水・防寒とひと目で分かるぐらいに靴底が厚い. 今までスニーカーしか履いてなかったので硬いし足音がすごいが,慣れてくると変わるのだろうか.

自分の足の特性についてあまり調べてなくて,サイズとレビュー欄だけて判断してインターネットで靴を買っている. まだ困った様子は見られないがこの先いつ困ることになるとも限らない.

二条発鳥取経由京都着

utgwkk.hateblo.jp

前回の鳥取旅行から23ヶ月が経過して,ふといろいろが重なってJR大回りをしたくなりました. 近場だと京都→福知山→尼崎→京都などがありますが,もっと大回りしてもいけそうという判断やいろいろなどがあり,二条→(山陰)→鳥取→(因美線)→智頭→(智頭急行)→上郡→(山陽)→京都 という大回りをすることにしました.

gyazo.com

いろいろです. ちなみにこの翌日(今日ですね)の16:00にはレポート提出が控えているため,それに間に合うように帰ってくる必要がありますが,まあその日のうちに帰ってくれば余裕に決まってますね.

時系列

11/19

山陰本線 (二条→福知山)

起床がちょっと遅れたが普通列車だけでギリいけるということでスタート地点へ.

印刷|二条(京都)→京都|乗換案内|ジョルダン

ギリいけるルートです.園部以降で一本でもずれると普通列車だけでは1日で帰ってくることが不可能になり容赦がない,山陰は難しい.

順調のように見える.ここまでは順調だった.

トイレのために周囲にほとんど何もない駅で途中下車(次の列車は1時間後).普通列車のみでは今日中に帰れなくなる.フラグ回収のプロ.

どこまで行けるか不明だし,山陰と山陽の山の間でタイムアップは不安しかないので,鳥取の宿を予約.モバマスをしながら次の電車を待つ.寒い!!!!!!

既にだいぶ疲れているが,まだ京都府を出ていない.

山陰本線 (福知山→城崎温泉)

ここまでのあらすじ: 今日中に帰れなくなるし,まだ京都府を出ていない.次の電車まで1時間以上あるし,城崎温泉で途中下車する計画は消滅した…….

というわけで課金.普通列車のみで大回りとは何だったのか.足湯が恋しかった.

足湯で復活.しかし寒い!!!!!!!!

山陰本線 (城崎温泉鳥取)

鳥取までは行くだけなので特になにもありません.寒い!!!!!!!!

デレマスの6周年イベントの生中継を見ていたが,トンネルに入るたびに映像が途切れるので諦めてKindleに入ってた少女終末旅行を読む.

中間地点のはずだった鳥取に到着.23ヶ月が経過しても鳥取駅に自動改札はなかった.高速にホテルにチェックインして夕食を探すも,けっこう店が閉まってる…….

www.instagram.com

居酒屋に入ってオススメと書いてある定食を注文したら予想以上に多くてビビる.

ホテルに帰って翌日の旅程を確認したところ,普通列車だけでは朝8時に駅を出ないといけないことが分かる.

11/20

因美線智頭急行山陽本線東海道線 (鳥取→新大阪)

おはようございます.シャワーを浴びてからチェックアウト.

www.instagram.com

駅前のすなば珈琲で優雅な朝を迎える.時刻は9時を回っている.おみやげを買うなどした.

2度目の課金.普通列車のみとは何だったのか.普通列車で帰るとレポート出せないから仕方なかったんや…….

智頭から第三セクターであるところの智頭急行区間に入り,放送も流れて大はしゃぎしている様子.

山陽に出るとめちゃくちゃスムーズに帰ることができて笑う,山陰は難しい…….

新大阪まで帰ってきた.

東海道新幹線 (新大阪→京都)

「あれ?京都までスーパーはくとで行くんじゃなかったの?」と思われるかもしれないが,乗継割引というものがあってな……*1

無事に京都まで戻ってきた.

京都大学

鳥取を経由してレポートを提出することに成功.

まとめ

ギリいける,でいけるわけはないので素直に早起きしましょう.前日に酒を飲まないなどが吉です.鳥取に行こうとするたびに到着が遅れる呪いにかかっている気がする.

鳥取はいいところなので次はもっと余裕のある旅程で行きたいし,夕食によさそうな店が日曜日だからか軒並み閉まっていたのがちょっと残念.

*1:鉄道のオタクに教えてもらった.特急のみのときよりちょっと安くなる.

シェルで行ごとの数値の総和を取るとき paste と Arithmetic Expansion が使える

tl;dr

$ echo $((`paste -s -d+`))

で入力の各行の数値の総和が取れる. 入力ファイルを指定するときは次のように書く.

$ echo $((`paste -s -d+ < [filename]`))

負の整数も小数も計算できる.ただし小数は浮動小数であることに注意.

状況

たとえば,

100
200
300
400

みたいな入力があって,その各行の数値の総和をシェル上で取りたいというシチュエーションが訪れると思う. 私はこれまで awk で次のようなワンライナーを書いて計算していた.

$ awk '{s += $1} END {print s}' # => 1000

実はもっと短く書けるし,shとcoreutilsで完結しているのでシェルスクリプトでも気軽に書ける.このように;

$ echo $((`paste -s -d+`)) # => 1000

解説

paste -s -d+

paste は入力ファイルを行単位で連結するコマンドである.ファイル単位の zip と言えば伝わるかもしれない.

-s オプションを指定すると,1つのファイルの行を1行にまとめるようになる. -d オプションで,ファイルを連結するときの区切り文字を指定できる.デフォルトはタブ文字.

つまり,入力ファイルの行を区切り文字によって join することができるようになる.

$ paste -s -d+ # => 100+200+300+400

$((EXPR))

$((EXPR)) は,sh の機能*1で, EXPR を算術式として評価した結果で置換される.つまり,

$ echo $((1+2*3)) #=> 7

のように出力される.

まとめる

この2つと Command Substitution を組み合わせることで,

$ echo $((`paste -s -d+`)) # => 1000

が完成する.

参考

*1:もちろん bash でも zsh でも使える.

Flask の abort() と psycopg2 のコネクションがロックを手放さないことについて: 明示的に commit() を呼ぶとよい

tl;dr

  • psycopg2を使うときははSELECT句だけを実行する場合も明示的に conn.commit() をする.
  • コンテキストマネージャを使うとすっきり書ける.

現象と調査結果

FlaskとPostgreSQL(psycopg2)を用いたwebアプリケーションのテストで,404や403を返すテストの次に実行されるテストが終了しないという現象に遭遇した.

def db():
    if hasattr(g, 'db'):
        g.db = psycopg2.connect(...)
    return g.db


@app.route('/@<strting:username>')
def userpage(username):
    c = db().cursor()
    c.execute('SELECT * FROM users WHERE username = %s', (username,))
    user = c.fetchone()

    if user is None:
        abort(404)

    # return user page

ユーザーページを表示する処理を行っている.username に対応するユーザーがいない場合は404を返し,いる場合はユーザーページを返す.

この abort(404) に至るパスのテストの次に実行されるテストがいつまで経っても終了しない. 厄介なことにSIGINTを送っても(Ctrl-Cを叩いても)停止しない. curlで各ページを表示しても,1秒と経たずにレスポンスが返ってくるし,test_client の挙動を確かめてみたが特におかしいところはなさそうだった.

ところで,各テストケースの前にDBを初期化するを入れていることを思い出した.

class UserTest(unittest.TestCase):
    def setUp(self):
        app.init_db()

これはつまり次のような処理である.何の変哲もない,全テーブルのデータを削除する処理だ.

def init_db():
    with db() as conn:
        c = conn.cursor()
        c.execute('TRUNCATE users, posts, ... RESTART IDENTITY CASCADE')

いろいろ試した結果,この初期化処理で詰まっていることが分かった. とりあえず postgresql truncate slow で検索して次のページに着いた.

TRUNCATE に必要なロックが獲得できていないかもしれないから確認してみるとよいですよ,と書いてあり,実際に見てみると,確かに TRUNCATE がロックを獲得できないままになっている! psycopg2のドキュメントを見直してみると次のようなことが書いてあった. autocommit は既定では False であると書いてあり,その次に,

Warning: By default, any query execution, including a simple SELECT will start a transaction: for long-running programs, if no further action is taken, the session will remain “idle in transaction”, an undesirable condition for several reasons (locks are held by the session, tables bloat…). For long lived scripts, either ensure to terminate a transaction as soon as possible or use an autocommit connection.

The connection class — Psycopg 2.7.4.dev0 documentation

つまり,

SELECT * FROM users WHERE username = 'hoge';

だと思っていたものは,実は,

BEGIN;
SELECT * FROM users WHERE username = 'hoge';
-- NO COMMIT; The lock has not been released yet!

だったのだ! SELECTがトランザクションを中断しないままロックを保持していたというわけか? しかし return でレスポンス返したときはトランザクション終了してたようだし,デストラクタでCOMMITして自動的に接続を閉じるみたいな処理があったのだろうか. abort(404) は例外を送出するのでそれが呼ばれない?

ということで,明示的に conn.commit() を呼ぶようにコードを書き換えると,確かにロックが保持されたままにならずテストが無事に終了するようになった. コンテキストマネージャを使ってやるとすっきりした形で書ける.

with db() as conn:
    c = conn.cursor()
    c.execute('SELECT * FROM users')

結論

ドキュメントちゃんと読もう. しかし abort() で適切なリソース解放が行われていなかったとすればそれはそれで問題なのでは…….

読んだ本

今週かどうかがもう分からなくなってきた.

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

プログラミング言語を勉強していて,ある程度コードが書けるようになったという段階で読むべきだと思う.結局は人間がコードを読み書きするという前提(当たり前だが)を認識することができる.

すごい量の参考文献が書いてあって,読んだつもりを演出するために全部目を通すのか…….

ぜったい良いので買ってください.あわせて原作も買いましょう.

少女終末旅行 1巻 (バンチコミックス)

少女終末旅行 1巻 (バンチコミックス)

原作です.

全裸.合本版まだ安いので今のうちに買っておくといい.

Rust で簡単なシェルを実装した

ふとシェルを書いてみたくなったので書いた.cd と ls と外部コマンド実行まではできるようになった.

github.com

参考にしたページ.Cで書くよりはだいぶ高級なのでやりやすいと思う.

brennan.io

感想

パターンマッチがすごい

パターンマッチがとにかくすごいし,if let のような書き方はまさに他の言語にも欲しくなる. 久しぶりに静的型のある言語をがっつり書いたところとてつもない安心感に包まれた. 至るところに型が欲しい…….

所有権に身体がついていっていない

まだ Rust を学びたてなので,所有権がどうなるかが分かっていない. コンパイラが賢いのでその通りにやると通るようになる,ということがよくあった. もうちょっとちゃんと理解したい.

新しい言語をやると刺激になる

いきなり思い立って何かを実装してみるとき,普段使い慣れた言語で実装することが多いと思うけど,あえて新しい言語を使って実装してみるとあちこちに学びがあって楽しい. 最初はなにも分からないのでリファレンスを参照しつつ書くことになるけど,うまい読み替えでしのいだり,だんだんとわかりを得てきたりする.

使い慣れた言語でやると確かにすぐ実装できるんだけど,新しい言語でやるとはるかに多くの学びがある.

シェルが動くと楽しい

シェルが動くと楽しい!!