ツイートに含まれるURLを高速に抽出するライブラリ、つくりました
2016/03/13 お知らせ: このライブラリの内容を含めて twitter-text 完全互換のライブラリを作りました。こっちがメインになります。
お知らせ終わり。
URI教の皆さんへ: Twitter が URL って言ってるからこっちに統一しました。許して。
はい、タイトルの通りです。言いたいことは以上です。
twitter-text 問題
神(Twitter)は言われた。「ライブラリあれ。」こうして、 twitter-text があった。神は twitter-text を見て、良しとされた。
「よくねーよ C# 版出してくれよ!」
こんな声にお答えしたライブラリは数あれど(メンテナンスされてるとは言ってない)、そもそも twitter-text の Extractor(URLとかハッシュタグとか抽出してくるやつ)は正規表現頼りで、連続して動かすと非常に遅いわけです。
そもそも、 Twitter クライアント作者(僕は違う、よね)が twitter-text を求めるのは、あのクソみたいな t.co とかいうやつを考慮してツイートの文字数を計算し、 140 文字をオーバーしていないかをチェックするためですよね。つまりこのクソ長い正規表現を 1 文字入力するたびに走らせなければなりません。おえー
正規表現は文字列を順番に読み進み、一致しなければ少し戻り、をマッチする/しないが確定するまで繰り返します。単純な文字列ならいいんですけどね、 t.co の判定基準とかだるすぎるし、人間にとってだるいんだから、コンピュータにとってはつらすぎますよね。知らんけど。
そこで、つくりました
Azyobuzi.TwitterUrlExtractor(かっこいい名前が思いつかなかった)は、最も効率的な方法(だと僕が思っている方法)で URL を抽出します。これでツイート内容のテキストボックスに「ああああああああああああ(x1000くらい)」と無駄に入力しても重くならないようになりますね!
仕組みは簡単(ではない)。
- 「.」を探す (http://twitter.(←)com/azyobuzin)
- 逆戻りしてドメインとして有効な部分と「http://」があるかないかを探す ((→)http://twitter.com/azyobuzin)
- 「.」の後ろもドメインとして有効な部分を探す (http://twitter.com(←)/azyobuzin)
- 有効な TLD かどうかチェック
- ポート・パス・クエリを読み取る
- 完了!
と書くのは簡単だけど、イレギュラーな判定基準が多すぎて死にそうになりましたが、見事 twitter-text に入ってる extract.yml のテストを全部通過させることができました!
まとめ
(たぶん)twitter-text 互換の URL 検出を結構高速(twitter-text-csの17倍, Releaseビルドだともっとやばい)に行うことができます。強い!
追記
twitter-text の正規表現に RegexOptions.Compiled をつけてやったら逆に低速化したんだけど
— 櫻井桃華 (@azyobuzin) February 23, 2016
なんでや!なんでコンパイルしたほうが正規表現遅くなってるんやおかしいやろwww
— 櫻井桃華 (@azyobuzin) February 23, 2016
ASP.NET 5アプリをUpstartでデーモン化してnginxでリバースプロキシするお話
タイトルで内容が全部終わった。要するに「もう Hello, World だけして満足する時代は終わった。Linuxの本番環境に乗せるぞ」ということです。
dnu publish
合言葉は
dnu publish --configuration Release --no-source --framework dnxcore50
これで CoreCLR 向けにリリースビルドされます。 --no-source を指定することで実行時にソースコードを利用せずコンパイル済みアセンブリを使用するのでパフォーマンスもメモリ使用量も削れるはず。
Upstart スクリプト
start on runlevel [2345] stop on runlevel [016] exec DNXのパス/runtimes/dnx-coreclr-linux-x64.1.0.0-rc1-update1/bin/dnx \ -p ソースコード/src/アプリ名/bin/output/approot/packages/アプリ名/バージョン/root \ web \ --server.urls http://localhost:ポート/ respawn
nginx
server { listen 80; location / { proxy_pass http://localhost:ポート/; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Connection "keep-alive"; } }
Microsoft.AspNet.HttpOverrides パッケージを使うと X-Forwarded ヘッダーをうまいこと使ってくれます。
Connection: keep-alive は指定しておかないと chunked なレスポンスが返ってこなくなります。謎い。
詳しい話
dnu publish することで、パッケージが全コピーされるので、ユーザーにかかわらず実行できるようになります。そもそも publish は別のマシンでやって、それを本番環境にコピーするのが一番いい方法ですね。ただし、 Windows でやって Linux で動かすとなると、 OS 依存のパッケージが違ってくるので死ぬかも。
まとめ
とりあえずこれで https://twpollapi.azyobuzi.net/ は動いているので、 ASP.NET 5 は Linux でも使い物になります。たぶん。
ICompileModule でメタプログラミングするやつ
あけましておめでとうございます。今週のお題「今年こそは」だそうですが、今年こそは強い人間になりたいですね。というのも最近どんどん挑戦することが嫌になってきて……。
本題行きます。ASP.NET タグが指定してあることからわかるように、今回も DNX の話です。DNX には C# のコンパイル時にコードを書き換えることができる機能があります。一時期 Yeoman の吐くテンプレートで Razor の事前コンパイルに使われていたようですが、今試したところなくなっていましたね。。というわけでこれの使い方を紹介していきます。
注意
ASP.NET5 RC1-final 時点での情報です。将来 Roslyn 自体にこの機能がぶちこまれて DNX 側の機能ではなくなる可能性もあります。
非同期処理のデータ伝達を楽にする System.Threading.Tasks.Channels
corefxlab Advent Calendar 12 日目です。頓挫しかしてねえ!!!
今回は System.Threading.Tasks.Channels の紹介です。また無駄に詳しくやっていこうと思います。
(というかこれ紹介でも解説でもなくリファレンスマニュアルってやつでは)
実をいうと、これに関しては README.md にとっても詳しく書いてあるので書く必要ない気がしなくもないですが、日本語でググれない問題を解決したり、僕の承認欲求を満たしたりするなどの副作用がありそうなので頑張っていきましょう。
- 注意
- チャネルってなんぞや
- System.Threading.Tasks.Channels の意義
- インストール
- IChannel<T> インターフェイス
- チャネルの種類
- Create / CreateUnbuffered
- ReadFromStream / WriteToStream
- CreateFromTask
- CreateFromEnumerable
- Select
- 終わり
注意
この記事の最終更新日は 2015/12/12 です。変化の多いリポジトリで、仕様も固まっていないことから、ここで説明する内容はすぐに古くなる可能性があります。
というかこの記事を書いている今現在も issue の変動が見られるので本当に変更が入りまくりそうです。
チャネルってなんぞや
僕の説明が正しい自信がないのでちゃんと理解して使いたい方はググってください。
チャネルは非同期処理においてデータ競合を防ぎながら、送信者から受信者へデータを伝達する方法のひとつです。送信者と受信者は一対一で、ひとつのデータが複数の受信者に渡るということが発生しないようになっているので、うまく使えば安全なキューや非同期処理の戻り値として利用できます。
System.Threading.Tasks.Channels の意義
何より C# には await があります。そこで、データの送受信の待機処理を直線的に書くことができ、読みやすく、流れを理解しやすいコードになります。
非同期処理におけるデータの受け渡しと加工は今までも System.Threading.Tasks.Dataflow パッケージで提供されてきましたが、これは流れを図で表したものを、ブロック単位でつなげていく、というような使い方をするものでした。対して System.Threading.Tasks.Channels では、加工部分には関与せず、データの受け渡しのみをシンプルに行うことができる設計になっています。
System.Buffers.ManagedBufferPool を理解する
corefxlab Advent Calendar 6日目です(大嘘)。
昨日の記事の補足というか、こっちもちゃんと理解していないと無駄が多くなりそうということで書いておきます。
この記事の最終更新日は 2015/12/06 です。変化の多いリポジトリで、仕様も固まっていないことから、ここで説明する内容はすぐに古くなる可能性があります。
- ManagedBufferPool の基本的な使い方
- インスタンスを作成する
- バッファの取得、拡張、破棄
- さぁもっと深入りするぞ
- 作成される配列
- Rent と Return の挙動
- 効率の良い使い方
- ReturnBuffer の不正利用の危険
ManagedBufferPool の基本的な使い方
ManagedBufferPool は配列を使いまわして GC 回数を減らすことが目的のもので、 System.Buffers アセンブリに含まれています。インストール方法は昨日の記事を見ればわかると思います。
ManagedBufferPool<T> ということでジェネリックパラメータを持っていますが、ソースコードを読んだ感じだと byte 以外は想定されていなさそうです。
インスタンスを作成する
コンストラクタはこのようになっています。
ManagedBufferPool(int maxBufferSizeInBytes = 2048000)
maxBufferSizeInBytes という名前がついていますが、今のところ要素数なのでバイト単位ではありません。
maxBufferSizeInBytes で指定されたサイズを超えるバッファを要求した場合には、その byte 配列は再利用されることはありません。
また、コンストラクタを呼ぶほかに、デフォルトのインスタンスが存在しています。
ManagedBufferPool<byte>.SharedByteBufferPool
byte 配列専用なのになんでジェネリッククラス内に定義したのかさっぱりわかりませんが、とにかくこのように取得しておけばいいと思います。なお、このクラスは使い回せば使い回すほど効果が高いので、基本的に SharedByteBufferPool を使うことをおすすめします。
無駄なく文字列生成! System.Text.Formatting の使い方と動作の流れ
Advent Calendar の季節ですが、何にも参加していないので好き勝手書いていきたいと思います。さて、今回は .NET Core Lab プロジェクトで開発されている System.Text.Formatting について、主な使い方と、さらに深入りして使うには、ということで書いていきます。
普通の使い方を知りたいがために訪れた方は「基本的な使い方」まで読んでいただければと思います。その先は闇が深くなります。
- 注意
- System.Text.Formatting の目的
- インストール
- Formatter の種類
- StringFormatter
- BufferFormatter
- StreamFormatter
- 基本的な使い方
- Append
- Format
- IBufferFormattable を実装する
- 実装例
- IFormatter を実装する
- FormattingData プロパティ
- FreeBuffer プロパティ
- CommitBytes(int bytes) メソッド
- ResizeBuffer メソッド
- 実装例
- IFormatter を直接触ってみる
- まとめ
注意
この記事の最終更新日は 2015/12/06 です。変化の多いリポジトリで、仕様も固まっていないことから、ここで説明する内容はすぐに古くなる可能性があります。
この記事の中で何回か出てくる ManagedBufferPool について別の記事に詳しく書きました。ご確認ください。
System.Text.Formatting の目的
System.Text.Formatting は従来 StringBuilder を使って行ってきた処理を、もっとメモリアロケーションを減らし、効率良く行うことが目的のライブラリです。いちいち ToString を呼び出したりせず、直接バッファに書き込む形をとることで、 GC の負担を減らすことができます。また .NET の内部では文字列は UTF-16 で処理されますが、 web などの用途では UTF-8 で出力することが求められることがあるので、可能な場合は直接 UTF-8 バイト列として書き込んだりします。
hosting.json リファレンス
ASP.NET5 RC1-final の情報です。
設定項目一覧
キー | 説明 |
---|---|
ASPNET_ENV / Hosting:Environment | Development / Staging / Production のいずれかが基本 |
webroot | 静的ファイル配信に使う wwwroot ディレクトリのパス |
app / Hosting:Application | 実行するwebアプリケーションが含まれるアセンブリの名前(StartupAssemblyName) |
server / Hosting:Server | サーバーが含まれるアセンブリの名前(ServerFactoryLocation) |
HTTP_PLATFORM_PORT | デフォルトのポート番号(IIS用) |
Hosting:DetailedErrors | true や1 を指定すると「Development」環境でwebアプリの初期化に失敗したときに、例外の情報をレスポンスに載せるようになります。 |
書き方
:
がオブジェクトの区切りです。それだけ気をつければ。
{ "webroot": "ウェブソイヤルート", "Hosting": { "Environment": "Staging", "Server": "Microsoft.AspNet.Server.Kestrel" } }
コマンドライン引数で--config
を指定すると hosting.json 以外のファイルを読みこませることもできます。あとコマンドライン引数と環境変数からも読み取ってくれます。そのへんは公式ドキュメントを読んでください。
Configuration — ASP.NET 0.0.1 documentation