byte[]をstringへ高速に変換する
生のバイト配列を文字列に変換したい場面は割とある。ログを残したいときとか。いくつもの方法があるようだが、単純に変換した場合と速度にこだわった実装とでどれくらいの差があるのか実際に確かめてみた。
Method | Mean | Error | StdDev | Gen 0/1k Op | Gen 1/1k Op | Gen 2/1k Op | Allocated Memory/Op |
---|---|---|---|---|---|---|---|
StringJoin | 88.245 us | 10.5631 us | 0.5790 us | 10.9863 | - | - | 33.79 KB |
StringBuilder1 | 88.994 us | 3.9169 us | 0.2147 us | 10.9863 | - | - | 33.82 KB |
StringBuilder2 | 69.993 us | 10.3178 us | 0.5656 us | 10.9863 | - | - | 33.76 KB |
StringBuilderFormat | 149.418 us | 20.2449 us | 1.1097 us | 43.9453 | - | - | 135.32 KB |
Lookup | 2.355 us | 0.2481 us | 0.0136 us | 2.5482 | - | - | 7.85 KB |
Lookup_Separator | 2.743 us | 0.1258 us | 0.0069 us | 3.8147 | - | - | 11.75 KB |
前3つが単純なやり方、後ろ2つが速度重視の実装だ。文字列変換処理に時間がかかるので、速度重視の実装では変換処理を行わないようにしている。byte
程度なら256通りしかないわけで予め全部変換しておいて、そこから引き出すのが究極に速い。ユーティリティとして用意しておくのが良いだろう。
StringJoin(string.Join(",", m_values.Select((x) => x.ToString("X2")))
)が最も単純と思われる方法で私は普通はこう書く。string.Join()
では内部でStringBuilder
が使われるためStringBuilder1/2と大きい違いはない。
StringBuilder1と2は明示的にStringBuilder
で組み上げてみたもの。ちょっと横道にそれて、Select()
で変換してからforeach
回すのと、配列をforeach
で回してから変換するのの違いを一応確認したが、やはり後者の方が速い。
StringBuilderFormatは.ToString("X2")
ではなくStringBuilder.AppendFormat("{0:x2},")
で変換してみたもの。フォーマットはかなり遅い。
Lookupは区切り文字なし、Lookup_Separatorは区切り文字ありだがあまり差はなくどちらもとても速い。
参考