I released QjsIpc 🎉

Learning WASM 4 ~ 8 の成果をライブラリ化して公開した。

JS側では今回作成したQuickJSの拡張モジュールでるipcモジュールを使用し、プロシージャを登録して、最終的にlistenメソッドを実行する

import * as ipc from 'ipc';

ipc.register('echo', function (payload) {
  return payload;
});

ipc.listen();

.NET側では、QjsIpcEngineのインスタンスを作成し、JSファイルと実行フォルダを指定してQuickJSを実行する。

実行した後は、InvokeAsyncメソッドでJS側に登録したプロシージャを実行できる。

using QjsIpc;

await using var engine = new QjsIpcEngine();

engine.Start(new QjsIpcOptions
{
    ScriptFileName = "main.js",
    AllowedDirectoryPath = Environment.CurrentDirectory,
});

var message = await engine.InvokeAsync<string>("echo", "Hello, World!");

Console.WriteLine(message);

.NET側にプロシージャを用意し、JS側から呼び出すこともできる。

.NET側にプロシージャホストとなるクラスを作成し、そのインスタンスをMethodHostオプションに設定する。
生やすメソッドは、値でもTaskでもValueTaskでも大丈夫。

public class Host
{
    public int HostAdd(int a, int b) => a + b;

    public Task<string> HostStringTask() => Task.FromResult("host value");

    public async Task<string> HostStringAsync() {
        await Task.Delay(100);
        return "host value";
    }

    public async ValueTask<string> HostStringValueAsync() {
        await Task.Delay(100);
        return "host value";
    }
}

public class Program
{
    public static async Task Main(string[] args)
    {
        await using var engine = new QjsIpcEngine();

        engine.Start(new QjsIpcOptions
        {
          ScriptFileName = "main.js",
          AllowedDirectoryPath = Environment.CurrentDirectory,
          MethodHost = new Host()
        });

        await engine.InvokeAsync('createMessage', "iwate");
    }
}

JS側ではipc.invokeメソッドで呼び出せる。戻り値はPromise。

import * as ipc from 'ipc';

ipc.register('createMessage', async function (name) {
  const value = ipc.invoke('HostAdd', 100, 200);
  return `Hi, ${name}. The result of HostAdd(100, 200) is ${value}`;
});

ipc.listen();

ベンチマークもとってみたが、想像通り速くはない。けど使えないほどではない。

自分の実装の中で遅い部分の検討はついてて、.NET<->JS間を1バイトずつやり取りしてるのでまあ遅い。

wasmのmemory使ってページ(64kb)ごとにやり取りすればもっと早くなるかな。今後に課題。

// * Summary *

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22000
11th Gen Intel Core i7-1165G7 2.80GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK=6.0.200-preview.21617.4
  [Host]     : .NET 6.0.1 (6.0.121.56705), X64 RyuJIT  [AttachedDebugger]
  DefaultJob : .NET 6.0.1 (6.0.121.56705), X64 RyuJIT


|           Method |       Mean |     Error |    StdDev |
|----------------- |-----------:|----------:|----------:|
|             Echo |   303.7 us |  28.22 us |  81.42 us |
|        HostValue |   456.2 us |  41.25 us | 120.97 us |
|              Ejs | 1,414.2 us |  91.87 us | 269.43 us |
| EjsWithHostValue | 1,499.9 us | 121.33 us | 340.22 us |

You'll only receive email when they publish something new.

More from iwate
All posts