9
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【C#】.NET6のBlazor WebAssemblyのJS呼び出しは200倍早い

Posted at

導入

前回記事( https://qiita.com/Kujiro/items/f6d09167031320ae17bb )に引き続き、Blazor WebAssemblyのパフォーマンス改善の話です。
.NET6でC# => JS でのバイト配列の取り扱いが変わりました。破壊的変更ということでMicrosoftの方でも紹介されています。( https://docs.microsoft.com/ja-jp/dotnet/core/compatibility/aspnet-core/6.0/byte-array-interop )
実際何が変わったか試してみました。

何が変わったか

まずこんな感じのJavascriptを書きます。ファイルはwwwroot直下に配置するものとします。

TestScript.js
export function ByteArrayTest(arg) {
    console.log(arg);
}

次にC#から呼び出します。

Index.razor
// @inject IJSRuntime JSRuntime; <= これが書いてある前提
private async Task Hoge()
{
    var module = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./TestScript.js");
    var array = Enumerable.Range(1, 1 << 20).Select(x => (byte)x).ToArray();
    await module.InvokeVoidAsync("ByteArrayTest", array);
}

.NET5で実行するとBase64エンコードされた文字列が表示されます。

console
AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFy
(以下略、1.4MB)

.NET6で実行するとUint8Arrayが表示されます。

console
Uint8Array(1048576)

確かに破壊的変更です。破壊的変更に結構慎重なC#/.NETで破壊的変更になるということは Base64エンコードのオーバヘッドが消えた分のパフォーマンス改善は結構大きいのでしょうか?
ちなみに、C#側のbyte[]とJS側のUInt8Arrayは流石に共有はされていません。それぞれ独立に書き換えられます。

パフォーマンス測定

実際どれくらい差が出るのか試してみました。
PC環境は前回の記事と同様、.NET5/.NET6ともAOTはなしでReleaseビルドにします。
JS側の関数は空にします(単に呼び出しのオーバヘッドだけを測ります)

TestScript.js
export function ByteArrayTest(arg) {}

C#側のコードは10回実行して平均と最大をとります。
引数のサイズは1MBになるようにしています。

Index.Razor
// @inject IJSRuntime JSRuntime
private async Task DoCallTest()
{
    var module = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./TestScript.js");
    var array = Enumerable.Range(1, 1 << 20).Select(x => (byte)x).ToArray();
    List<TimeSpan> list = new();

    for (int i = 0; i < 10; i++)
    {
        var stopwatch = System.Diagnostics.Stopwatch.StartNew();
        await module.InvokeVoidAsync("ByteArrayTest", array);
        stopwatch.Stop();
        list.Add(stopwatch.Elapsed);
    }
    Result = ($"arg-size={array.Length},ave:{list.Select(x => x.TotalMilliseconds).Average()}ms,max={list.Max().TotalMilliseconds}ms");
}

結果

環境 平均 最大
.NET5 450ms 471ms
.NET6 2.02ms 10.9ms

220倍早いです。全然違いますね。

感想

Span<T>も渡せたらいいのに...
JS呼び出しの目的ってJS相互運用のみならず単にIndexedDB使いたいとかWeb Workers API使いたいとかっていうケースも多いので
stringとかもそのままUnit8Arrayで渡せると高速化できそうですね。

9
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?