みなさんこんにちは。
前の記事に加えて、
kirill_danshinとの興味深い対話があり
ました 。 最後に、私たちはそれをやった。 Meet-
efaceconv 、go generateのツール。これを使用すると、インターフェイス{}から割り当てなしで型をキャストでき、
最大 4倍高速になります。
どのように作業するのですか?
簡単です:
- インストール:github.com/t0pep0/efaceconvを取得します
- go generate // go:efaceconvをソースに生成する呼び出しを追加します
- 変換が必要なタイプを説明します(以下を参照)
- 生成してお楽しみください(ZYをボーナスとして-生成されたコードを100%カバレッジでテスト)
型を記述する方法
繰り返しますが、すべてが簡単です。 タイプはコメントで説明されています。 記述形式は次のとおりです。
例:
パッケージのディレクトリでgo generateを実行すると、2つの新しいファイルが表示されます。
efaceconv_generated.go-生成されたメソッド
efaceconv_generated_test.go-それらのテストとベンチマーク
demo.goの例:
efaceconv_generated.go:
efaceconv_generated_test.go:
ご覧のとおり、efaceconvは次の形式のメソッドを生成します
Eface2< >(arg interface{}) (*< >, bool)
それらのドキュメント、テスト、ベンチマークに加えて、パフォーマンスゲインを比較できるように、クラシックキャストタイプ(v、ok:= arg。(Type))のベンチマークも生成されます。
仕組み
(
以前の記事から)空のインターフェイスは、2つのフィールド(* TypeDescriptorとオブジェクトへのポインター)を持つ構造にすぎません。 TypeDescriptorは、1つの型からのすべての空のインターフェイスに対して、それぞれの型の単一のインスタンスで実行時に生成されます* TypeDescriptorは等しくなり、TypeDescriptor自体を解析する必要はありません。 ポインタの数値を単純に比較することができ、それらが一致する場合でも、必要な型があることを確認しながら、オブジェクトへのポインタを返すことができます。
なぜこれが標準的な方法より速いのですか?
TypeDescriptorsを比較した後の型キャストの標準的な方法は、値によってデータをコピーします。ソースオブジェクトへのポインタを与えるだけです
では、なぜGoの作者はこれをしなかったのでしょうか?
これは安全ではありません。 より正確にはそうではありませんが、不変のデータ型(文字列、スライス、配列)を使用している限り、安全です。 不正確なコード記述で不変ではないデータ型を使用する場合、副作用が発生する可能性があります。
すでにどこかで使用されていますか?
kirill_danshinは彼のプロダクションで最初のバージョンを導入しました。結果については信頼できませんが、
コミットによって判断
すると、彼は満足しています。
数字はどこですか? パフォーマンスと割り当てについて
BenchmarkEface2SByte-4 100000000 11.8 ns/op 0 B/op 0 allocs/op --- BENCH: BenchmarkEface2SByte-4 efaceconv_generated_test.go:33: &[] true efaceconv_generated_test.go:33: &[] true efaceconv_generated_test.go:33: &[] true efaceconv_generated_test.go:33: &[] true efaceconv_generated_test.go:33: &[] true BenchmarkSByteClassic-4 30000000 50.4 ns/op 32 B/op 1 allocs/op --- BENCH: BenchmarkSByteClassic-4 efaceconv_generated_test.go:48: [] true efaceconv_generated_test.go:48: [] true efaceconv_generated_test.go:48: [] true efaceconv_generated_test.go:48: [] true efaceconv_generated_test.go:48: [] true BenchmarkEface2String-4 100000000 11.1 ns/op 0 B/op 0 allocs/op --- BENCH: BenchmarkEface2String-4 efaceconv_generated_test.go:76: 0xc42003fee8 true efaceconv_generated_test.go:76: 0xc420043ea8 true efaceconv_generated_test.go:76: 0xc420043ea8 true efaceconv_generated_test.go:76: 0xc420043ea8 true efaceconv_generated_test.go:76: 0xc420043ea8 true BenchmarkStringClassic-4 30000000 45.3 ns/op 16 B/op 1 allocs/op --- BENCH: BenchmarkStringClassic-4 efaceconv_generated_test.go:91: true efaceconv_generated_test.go:91: true efaceconv_generated_test.go:91: true efaceconv_generated_test.go:91: true efaceconv_generated_test.go:91: true BenchmarkEface2SInt-4 100000000 11.6 ns/op 0 B/op 0 allocs/op --- BENCH: BenchmarkEface2SInt-4 efaceconv_generated_test.go:119: &[] true efaceconv_generated_test.go:119: &[] true efaceconv_generated_test.go:119: &[] true efaceconv_generated_test.go:119: &[] true efaceconv_generated_test.go:119: &[] true BenchmarkSIntClassic-4 30000000 50.5 ns/op 32 B/op 1 allocs/op --- BENCH: BenchmarkSIntClassic-4 efaceconv_generated_test.go:134: [] true efaceconv_generated_test.go:134: [] true efaceconv_generated_test.go:134: [] true efaceconv_generated_test.go:134: [] true efaceconv_generated_test.go:134: [] true PASS
悪役! 可変タイプ用に作成されたとおりにすべてを実行し、コードに奇妙な動作が発生しました!
SWSSUPD: 考えられない場合、起こりうる問題について 。