Blazor wasm 调用 javascript,传递大数组非常慢
Blazor wasm invoke javascript, pass large array is very slow
我有一个 blazor wasm 应用程序。因为我正在调用一个 javascript 函数来接收一个双精度数组。
这非常慢,尤其是当数组很大时。
有关测试,请参阅以下代码:
javascript ("test.js"):
function testSumArray(array) {
var t0 = performance.now();
sumArray(array);
var t1 = performance.now();
console.log('From JS, time to sum: ' + (t1 - t0) / 1000 + ' s');
}
function sumArray(array) {
var i;
var s = 0;
for (i = 0; i < array.length; i++) {
s += array[i];
}
return s;
}
和c#代码(index.razor):
@page "/"
@inject IJSRuntime JSRuntime;
@using System.Text
@using BlazorWasmOnlyTest.Shared
<h1>Hello, world!</h1>
Welcome to your new app.
<div class="container">
<div class="row mb-2">
<div class="col">
<button class="btn btn-primary" @onclick="@TestInvokeJS">Test invoke js</button>
</div>
</div>
</div>
@code {
private int _id;
private string _status = "";
private DataInputFileForm _dataInputFileForm;
private async void TestInvokeJS()
{
var n = 100000;
var array = new double[n];
for (int i = 0; i < n; i++)
{
array[i] = i;
}
var w = new System.Diagnostics.Stopwatch();
w.Start();
await JSRuntime.InvokeVoidAsync("testSumArray",array);
w.Stop();
Console.WriteLine($"C# time to invoke js and sum: {w.ElapsedMilliseconds/1000:F3} s");
}
}
并完成 - index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>BlazorWasmOnlyTest</title>
<base href="/" />
<link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
<link href="css/app.css" rel="stylesheet" />
<script src="js/test.js"></script>
</head>
<body>
<app>Loading...</app>
<div id="blazor-error-ui">
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss"></a>
</div>
<script src="_framework/blazor.webassembly.js"></script>
</body>
</html>
运行 这一次在我的机器上给出了以下输出:
From JS, time to sum: 0.0037800000282004476 s
C# time to invoke js and sum: 7.000 s
这似乎是一个相当高的开销时间......有谁知道是否有办法加快这个速度(真正的功能做了我目前无法在 Blazor/C# 中做的事情 - 更新层Leaflet)
编辑:
我已经尝试了 here 描述的同步方法,执行时间没有任何差异。
c#:
var jsInProcess2 = (IJSInProcessRuntime)JSRuntime;
jsInProcess2.InvokeVoid("testSumArray", array);
js: javascript 与上面的 testSumArray
相同。
编辑 2:
我尝试通过同步互操作传递 JSON 字符串:
c#:
var jsInProcess3 = (IJSInProcessRuntime)JSRuntime;
var array_json3 = System.Text.Json.JsonSerializer.Serialize(array);
jsInProcess3.InvokeVoid("testSumArray3", array_json);
js:
function testSumArray3(array_json_string) {
var t0 = performance.now();
var array = JSON.parse(array_json_string);
var s = sumArray(array);
var t1 = performance.now();
console.log('From JS, time to sum: ' + (t1 - t0) / 1000 + ' s');
console.log('Array sum = ' + s);
}
以及 JSON 字符串和 InvokeUnmarshalled js 互操作调用:
c#:
var jsInProcess4 = (Microsoft.JSInterop.WebAssembly.WebAssemblyJSRuntime)JSRuntime;
var array_json4 = System.Text.Json.JsonSerializer.Serialize(array);
jsInProcess4.InvokeUnmarshalled<string,string>("testSumArray4", array_json4);
js:
function testSumArray4(array_mono_json_string) {
var t0 = performance.now();
const array_json_string = BINDING.conv_string(array_mono_json_string);
var array = JSON.parse(array_json_string);
var s = sumArray(array);
var t1 = performance.now();
console.log('From JS, time to sum: ' + (t1 - t0) / 1000 + ' s');
console.log('Array sum = ' + s);
}
所有方法花费的时间大致相同,需要 6-7 秒才能完成(javascript 函数中大约需要 0.0015-0.006 秒)。
我试图弄清楚如何使用 file 中的 BINDING.mono_array_to_js_array
来调用未编组传递数组,但这会引发一个很长的错误。
c#:
var sum = jsInProcess4.InvokeUnmarshalled<double[],double>("testSumArray5",array)
js:
function testSumArray5(array_in) {
var t0 = performance.now();
var array = BINDING.mono_array_to_js_array(array_in);
console.log(array[0]);
var s = sumArray(array);
var t1 = performance.now();
console.log('From JS, time to sum: ' + (t1 - t0) / 1000 + ' s');
console.log('Array sum = ' + s);
return s;
}
刚刚找到在 js 中使用 .net byte 或 float 数组的方法
c#:
[Inject] //Injected JSRuntime from Blazor DI
private IJSRuntime JSRuntime { get; set; }
byte[] bytes1;
float[] floats2;
...
if (JSRuntime is IJSUnmarshalledRuntime webAssemblyJSRuntime)
{
webAssemblyJSRuntime.InvokeUnmarshalled<byte[], float[], object>
("downloadArray", bytes1, floats2);
}
JavaScript:
function downloadArray(bytes1, floats2) {
// Easy way to convert Uint8 arrays
var byteArray = Blazor.platform.toUint8Array(bytes1);
// Adapted method above for float32
var m = floats2 + 12;
var r = Module.HEAP32[m >> 2]
var j = new Float32Array(Module.HEAPF32.buffer, m + 4, r);
}
这里的结果是在合理的时间段内分别来自 byte[] 和 float[] 的 Uint8Array 和 Float32Array 对象。
可能有任何获取 js 数组的方法,因为您可以从 ArrayBuffers 访问整个 .net 堆,例如 Module.HEAPU8(Uint8Array 内的堆)或 Module.HEAPF32(Float32Array 内的堆)并且可以轻松访问对象通过来自 InvokeUnmarshalled 参数的指针。
我有一个 blazor wasm 应用程序。因为我正在调用一个 javascript 函数来接收一个双精度数组。 这非常慢,尤其是当数组很大时。
有关测试,请参阅以下代码:
javascript ("test.js"):
function testSumArray(array) {
var t0 = performance.now();
sumArray(array);
var t1 = performance.now();
console.log('From JS, time to sum: ' + (t1 - t0) / 1000 + ' s');
}
function sumArray(array) {
var i;
var s = 0;
for (i = 0; i < array.length; i++) {
s += array[i];
}
return s;
}
和c#代码(index.razor):
@page "/"
@inject IJSRuntime JSRuntime;
@using System.Text
@using BlazorWasmOnlyTest.Shared
<h1>Hello, world!</h1>
Welcome to your new app.
<div class="container">
<div class="row mb-2">
<div class="col">
<button class="btn btn-primary" @onclick="@TestInvokeJS">Test invoke js</button>
</div>
</div>
</div>
@code {
private int _id;
private string _status = "";
private DataInputFileForm _dataInputFileForm;
private async void TestInvokeJS()
{
var n = 100000;
var array = new double[n];
for (int i = 0; i < n; i++)
{
array[i] = i;
}
var w = new System.Diagnostics.Stopwatch();
w.Start();
await JSRuntime.InvokeVoidAsync("testSumArray",array);
w.Stop();
Console.WriteLine($"C# time to invoke js and sum: {w.ElapsedMilliseconds/1000:F3} s");
}
}
并完成 - index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>BlazorWasmOnlyTest</title>
<base href="/" />
<link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
<link href="css/app.css" rel="stylesheet" />
<script src="js/test.js"></script>
</head>
<body>
<app>Loading...</app>
<div id="blazor-error-ui">
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss"></a>
</div>
<script src="_framework/blazor.webassembly.js"></script>
</body>
</html>
运行 这一次在我的机器上给出了以下输出:
From JS, time to sum: 0.0037800000282004476 s
C# time to invoke js and sum: 7.000 s
这似乎是一个相当高的开销时间......有谁知道是否有办法加快这个速度(真正的功能做了我目前无法在 Blazor/C# 中做的事情 - 更新层Leaflet)
编辑: 我已经尝试了 here 描述的同步方法,执行时间没有任何差异。
c#:
var jsInProcess2 = (IJSInProcessRuntime)JSRuntime;
jsInProcess2.InvokeVoid("testSumArray", array);
js: javascript 与上面的 testSumArray
相同。
编辑 2:
我尝试通过同步互操作传递 JSON 字符串:
c#:
var jsInProcess3 = (IJSInProcessRuntime)JSRuntime;
var array_json3 = System.Text.Json.JsonSerializer.Serialize(array);
jsInProcess3.InvokeVoid("testSumArray3", array_json);
js:
function testSumArray3(array_json_string) {
var t0 = performance.now();
var array = JSON.parse(array_json_string);
var s = sumArray(array);
var t1 = performance.now();
console.log('From JS, time to sum: ' + (t1 - t0) / 1000 + ' s');
console.log('Array sum = ' + s);
}
以及 JSON 字符串和 InvokeUnmarshalled js 互操作调用:
c#:
var jsInProcess4 = (Microsoft.JSInterop.WebAssembly.WebAssemblyJSRuntime)JSRuntime;
var array_json4 = System.Text.Json.JsonSerializer.Serialize(array);
jsInProcess4.InvokeUnmarshalled<string,string>("testSumArray4", array_json4);
js:
function testSumArray4(array_mono_json_string) {
var t0 = performance.now();
const array_json_string = BINDING.conv_string(array_mono_json_string);
var array = JSON.parse(array_json_string);
var s = sumArray(array);
var t1 = performance.now();
console.log('From JS, time to sum: ' + (t1 - t0) / 1000 + ' s');
console.log('Array sum = ' + s);
}
所有方法花费的时间大致相同,需要 6-7 秒才能完成(javascript 函数中大约需要 0.0015-0.006 秒)。
我试图弄清楚如何使用 file 中的 BINDING.mono_array_to_js_array
来调用未编组传递数组,但这会引发一个很长的错误。
c#:
var sum = jsInProcess4.InvokeUnmarshalled<double[],double>("testSumArray5",array)
js:
function testSumArray5(array_in) {
var t0 = performance.now();
var array = BINDING.mono_array_to_js_array(array_in);
console.log(array[0]);
var s = sumArray(array);
var t1 = performance.now();
console.log('From JS, time to sum: ' + (t1 - t0) / 1000 + ' s');
console.log('Array sum = ' + s);
return s;
}
刚刚找到在 js 中使用 .net byte 或 float 数组的方法
c#:
[Inject] //Injected JSRuntime from Blazor DI
private IJSRuntime JSRuntime { get; set; }
byte[] bytes1;
float[] floats2;
...
if (JSRuntime is IJSUnmarshalledRuntime webAssemblyJSRuntime)
{
webAssemblyJSRuntime.InvokeUnmarshalled<byte[], float[], object>
("downloadArray", bytes1, floats2);
}
JavaScript:
function downloadArray(bytes1, floats2) {
// Easy way to convert Uint8 arrays
var byteArray = Blazor.platform.toUint8Array(bytes1);
// Adapted method above for float32
var m = floats2 + 12;
var r = Module.HEAP32[m >> 2]
var j = new Float32Array(Module.HEAPF32.buffer, m + 4, r);
}
这里的结果是在合理的时间段内分别来自 byte[] 和 float[] 的 Uint8Array 和 Float32Array 对象。
可能有任何获取 js 数组的方法,因为您可以从 ArrayBuffers 访问整个 .net 堆,例如 Module.HEAPU8(Uint8Array 内的堆)或 Module.HEAPF32(Float32Array 内的堆)并且可以轻松访问对象通过来自 InvokeUnmarshalled 参数的指针。