.Net7.0 C#Ver11.0がリリースされました。
.Net7.0にすると、パフォーマンスが上がります。
いくつかベンチマークを流してみた感じでも、あちこち、少しずつ早くなっていますね。
ありがたいことです。
さて、同時期にリリースされた、C#Ver11.0
私が今、一番気になっているのは、utf8リテラルです。
例えば、OrderのJsonを作る場合、Jsonの中に、”buy”,”sell”とかを埋め込むわけです。
この”buy”,”sell”をstringで作ってしまうと、シリアライズするときに、UTF16→UTF8の変換が発生するので、stringは避けたいです。
じゃあどうするかというと、ReadOnlySpanか、byte[]かという感じです。
ReadOnlySpanの方が速いですが、Httpのリクエストするときに、asyncを使うわけで、asyncを使うとReadOnlySpanを引数で渡せません。
static ReadOnlySpan<byte> RosBuy() => new byte[] { (byte)'b', (byte)'u', (byte)'y' };
public Task Buy(double price, double size) => Order(RosBuy(), price, size);
public async Task Order(ReadOnlySpan<byte> side, double price, double size)
{
// ここでいろいろ処理
return;
}
こう書きたいのだけれども、OrderのReadOnlySpanはasyncで使えないと怒られる。
なので、byte[]を使って、次の様に書いていました。
static byte[] _buy = Encoding.UTF8.GetBytes("buy");
public Task Buy(double price, double size) => Order(_buy, price, size);
public async Task Order(byte[] side, double price, double size)
{
// ここでいろいろ処理
return;
}
byte[]をstaticで作っておくことで、UTF16→UTF8の変換は初回のみになっています。
その代わり、byte[]分のメモリを起動後ずっと使うことになります。まあ量はたいしたことはありませんが。
new byte[] { (byte)’b’, (byte)’u’, (byte)’y’ };
って書けば、初回の変換コストも外せるのですが、コードの書きやすさを優先しました。
さて、今回、utf8リテラルが入ったことで、まずこう変えられそうです。
static byte[] _buy = Encoding.UTF8.GetBytes("buy");
// ↓
static byte[] _buy = "buy"u8.ToArray();
書きやすさは似たようなものですが、悪化はしていないです。
初回のみなので、誤差のようなものですが、Utf16→Utf8の変換が無い分、速いです。
(気になってベンチマークも取りましたが、早くなっています。)
さて次に、”buy”をbyte[]ではなく、u8定数で渡すには、asynとReadOnlySpan のあたりを何とかしないといけません。
改造したものがこちら
public Task Buy(double price, double size) => Order("buy"u8, price, size);
public Task Order(ReadOnlySpan<byte> side, double price, double size)
{
byte[] json = GetJson(side, price, size);
return OrderCore(json);
}
public async Task OrderCore(byte[] json)
{
// ここでいろいろ処理
return;
}
パラメータから、Jsonを作る部分までは、asynを使わずに、同期プログラムで処理。
byte[]のjsonになってから、asyncのメインのプログラムを呼び出します。
これでやっとstaticのbyte[]を作っておくのから解放されました。
まあ、jsonのbyte[]も、キャッシュしたりいろいろ速度上げられますが、こちらは割愛。
なお、メソッド呼出のコストが増えるので、パフォーマンスとしては似たようなものにはなってしまいましたが。
utf8リテラルの使い方で、もっと良い方法とかご存じの方は、コメントとかで教えてもらえると嬉しいです。