c#Blazor WebAssembly在网页中多线程计算1000万次求余
在 Blazor WebAssembly 中实现多线程计算并获取线程 ID 是可行的,但需要正确配置多线程环境并处理线程安全和 UI 更新逻辑。以下是完整示例和检测方法:
一、准备工作:启用多线程支持
首先需确保项目已启用 WebAssembly 多线程,修改项目文件(.csproj
):xml
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly"><PropertyGroup><TargetFramework>net8.0</TargetFramework><Nullable>enable</Nullable><ImplicitUsings>enable</ImplicitUsings><!-- 启用多线程 --><WASMEnableThreads>true</WASMEnableThreads></PropertyGroup><ItemGroup><PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.0" /><PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.0" PrivateAssets="all" /></ItemGroup>
</Project>
同时,服务器需配置跨域隔离头部(确保 SharedArrayBuffer
可用)。如果使用 dotnet run
调试,需在 Properties/launchSettings.json
中添加:
"profiles": {"http": {"environmentVariables": {"ASPNETCORE_ENVIRONMENT": "Development","ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.WebAssembly.Server"},"applicationUrl": "http://localhost:5000"},"https": {"environmentVariables": {"ASPNETCORE_ENVIRONMENT": "Development","ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.WebAssembly.Server"},"applicationUrl": "https://localhost:5001;http://localhost:5000"}
}
跨域隔离头部会由 Blazor 开发服务器自动添加,生产环境需在服务器(如 Nginx/Apache)配置 Cross-Origin-Opener-Policy: same-origin
和 Cross-Origin-Embedder-Policy: require-corp
。
二、完整代码实现:多线程计算示例
修改 Counter.razor
,添加多线程计算逻辑:razor
@page "/counter"
@using System.Threading
@using System.Collections.Concurrent
@inject IJSRuntime JSRuntime<PageTitle>Counter</PageTitle><h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button><hr /><!-- 多线程测试区域 -->
<h3>多线程计算测试</h3>
<button class="btn btn-success" @onclick="StartMultiThreadCalculation">开始多线程计算</button>
@if (results.Any())
{<div class="mt-3">@foreach (var result in results){<p>线程 ID: @result.ThreadId | 耗时: @result.ElapsedMs ms | 7的倍数个数: @result.Count</p>}</div>
}@code {private int currentCount = 0;private List<ThreadResult> results = new();// 线程安全的结果队列(子线程写入,主线程读取)private ConcurrentQueue<ThreadResult> resultQueue = new();private void IncrementCount(){currentCount++;}// 线程计算结果模型private class ThreadResult{public int ThreadId { get; set; }public long ElapsedMs { get; set; }public int Count { get; set; }}// 启动3个线程private void StartMultiThreadCalculation(){results.Clear();resultQueue.Clear();// 线程1:计算 0 ~ 999万var thread1 = new Thread(CalculateMod7) { IsBackground = true };thread1.Start(0);// 线程2:计算 1000万 ~ 1999万var thread2 = new Thread(CalculateMod7) { IsBackground = true };thread2.Start(10_000_000);// 线程3:计算 2000万 ~ 2999万var thread3 = new Thread(CalculateMod7) { IsBackground = true };thread3.Start(20_000_000);// 启动定时器,定期检查结果队列并更新UI(子线程不能直接更新UI)var timer = new Timer(_ =>{// 切换到UI线程更新InvokeAsync(() =>{while (resultQueue.TryDequeue(out var result)){results.Add(result);}StateHasChanged(); // 强制刷新UI});}, null, 0, 100); // 每100ms检查一次}// 线程执行的计算逻辑:统计1000万个数中i mod 7 == 0的数量private void CalculateMod7(object? startObj){if (startObj is not int start) return;int end = start + 10_000_000; // 每个线程计算1000万次int count = 0;// 获取当前线程ID(托管线程ID)int threadId = Thread.CurrentThread.ManagedThreadId;var stopwatch = System.Diagnostics.Stopwatch.StartNew();// 执行计算for (int i = start; i < end; i++){if (i % 7 == 0){count++;}}stopwatch.Stop();// 将结果存入线程安全队列resultQueue.Enqueue(new ThreadResult{ThreadId = threadId,ElapsedMs = stopwatch.ElapsedMilliseconds,Count = count});}
}
三、关键实现说明
多线程创建:
使用System.Threading.Thread
创建 3 个线程,分别处理不同起始范围的计算(0~1000 万、1000 万~2000 万、2000 万~3000 万)。线程 ID 获取:
通过Thread.CurrentThread.ManagedThreadId
获取托管线程 ID(Blazor WASM 中支持,可区分不同线程)。线程安全与 UI 更新:
- 子线程不能直接更新 UI,需通过
ConcurrentQueue
存储结果(线程安全队列)。 - 使用
Timer
定期检查队列,通过InvokeAsync
切换到 UI 线程更新结果列表。
- 子线程不能直接更新 UI,需通过
计算逻辑:
每个线程循环 1000 万次,统计能被 7 整除的数字个数,记录耗时和线程 ID。
四、检测方法:验证多线程执行
观察线程 ID:
运行后点击 “开始多线程计算”,会显示 3 个不同的ThreadId
(如 3、4、5),说明确实启用了多线程。监控 CPU 使用率:
打开任务管理器(Windows)或活动监视器(Mac),计算过程中浏览器进程的 CPU 使用率会明显上升,说明多线程并行执行。网络请求检测:
打开浏览器开发者工具(F12)的 Network 面板,整个计算过程中无任何 HTTP 请求,证明逻辑由本地 WASM 线程处理,而非服务器回调。调试线程执行:
在CalculateMod7
方法中设置断点(需在浏览器开发者工具的 Sources 面板中找到对应代码),调试时可看到断点在不同线程中触发。
五、运行结果示例
点击 “开始多线程计算” 后,会显示类似结果:plaintext
线程 ID: 3 | 耗时: 235 ms | 7的倍数个数: 1428572
线程 ID: 4 | 耗时: 241 ms | 7的倍数个数: 1428571
线程 ID: 5 | 耗时: 239 ms | 7的倍数个数: 1428571
- 不同的
ThreadId
证明多线程生效。 - 耗时相近说明线程并行执行(总耗时约等于单线程耗时,而非 3 倍)。
总结
Blazor WebAssembly 中的多线程计算完全在客户端通过 WASM 执行,无 HTTP 回调。通过 Thread
类创建线程,ManagedThreadId
获取线程 ID,配合线程安全队列和 UI 线程切换,可实现多线程任务并正确显示结果。网络监控和线程 ID 验证可证明逻辑在本地 WASM 中执行。