8
5

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 1 year has passed since last update.

BlazorAdvent Calendar 2022

Day 4

Blazor WebAssemblyでマルチスレッドを使っていくための準備 (.NET 8を待っています)

Last updated at Posted at 2022-12-03

はじめに

今年は.NET 7でBlazor WebAssemblyでマルチスレッドがサポートされそうということで、このIssueをぼんやりと眺める日々を過ごしていました。

8月に.NET 7ではマルチスレッドに対応しないという内容が投稿され残念に思っていたら、.NET 7 RC2のリリースノートでマルチスレッドに関する内容に言及がありました。

wasm-experimentalワークロードはWeb Workersを使用したWebAssembly上のマルチスレッドの.NETアプリケーションをサポートするようになりました。これは新しい .NET ランタイム機能です。マルチスレッドのサポートはBlazor WebAssemblyアプリにはまだ統合されていませんが(.NET 8で予定)、実験的なWebAssembly Browser Appテンプレートを使ってプレビュー形式で試すことが可能です。

私は.NET 7 RC2からBlazor WebAssemblyでマルチスレッドを試すことができるのだと勘違いしていたのですが、試すことができるのはwasmbrowserのテンプレートでした。すみません。

それでも部分的にマルチスレッドを試すことができるのであれば、きっと.NET 8がリリースされてBlazor WebAssemblyにマルチスレッドを導入するときに役立つだろうと思い、動かしてみることにしました。

.NET 7 RC2のリリースノートで紹介されている例を動かしてみる

さきほどの.NET 7 RC2のリリースノートで紹介されている例を手元で動かしてみます。

wasm-experimentalワークロードをインストールします。

dotnet workload install wasm-experimental

アプリを作成します。

dotnet new wasmbrowser -o sampleapp1

プロジェクトファイルの<PropertyGroup><WasmEnableThreads>を追加します。

sampleapp1.csproj
<PropertyGroup>
  ...
  <WasmEnableThreads>true</WasmEnableThreads>
</PropertyGroup>

NuGetでMicrosoft.NET.WebAssembly.Threadingをインストールします。

dotnet add package --prerelease Microsoft.NET.WebAssembly.Threading

program.csに.NET 7 RC2のリリースノートのコードを反映させます。テンプレートが作成したJavaScript関係のコードをさわると、他の部分も編集する必要があるので、ここではそのままにしています。

program.cs
using System;
using System.Threading;
using System.Runtime.Versioning;
using System.Runtime.InteropServices.JavaScript;

[assembly: SupportedOSPlatform("browser")]

new Thread(SecondThread).Start();
Console.WriteLine($"Hello, Browser from the main thread {Thread.CurrentThread.ManagedThreadId}");

static void SecondThread()
{
    Console.WriteLine($"Hello from Thread {Thread.CurrentThread.ManagedThreadId}");
    for (int i = 0; i < 5; ++i)
    {
        Console.WriteLine($"Ping {i}");
        Thread.Sleep(1000);
    }
}

public partial class MyClass
{
    [JSExport]
    internal static string Greeting()
    {
        var text = $"Hello, World! Greetings from {GetHRef()}";
        Console.WriteLine(text);
        return text;
    }

    [JSImport("window.location.href", "main.js")]
    internal static partial string GetHRef();
}

dotnet runで実行して表示されたURLにアクセスすると、コンソールに以下のように出力されます。

console1.png

メインスレッドとは別に作成されたスレッドでPing 0 Ping 1 Ping 2と出力されています。

負荷をかけてみる

ここまでは.NET 7 RC2のリリースノートのコードをそのまま実行しました。マルチスレッドが必要なケースはCPUに負荷がかかるような場合が多いと思うので、そういった例を試してみます。さきほどのprogram.csを編集して無限ループで乱数を生成するようにします。

program.cs
static void SecondThread()
{
    Console.WriteLine($"Hello from Thread {Thread.CurrentThread.ManagedThreadId}");
    var random = new Random();
    while (true)
    {
        random.Next();
    }
}

スレッドが1個のとき

SecondThreadを呼び出した回数だけ乱数を生成するスレッドが作られます。私の8コア16スレッドCPUで1回だけ呼び出した場合は以下のようになりました。タスクマネージャーに表示されたCPUの使用率は10%前後でした。

multithreading1.png

スレッドが8個のとき

new Thread(SecondThread).Start();を8個並べて、スレッドが8個のときは以下のようになりました。タスクマネージャーに表示されたCPUの使用率は30%前後でした。

multithreading8.png

タスクマネージャーの画面下半分のCPUが活躍しているようで、マルチコアが活用されていることがわかります。

CPUのコア数を知るには?

マルチスレッドを使う場合にCPUのコア数を把握したい場合があると思うのですが、通常はSystem.Environment.ProcessorCountを見ればよいようです。

ただ、今回のコードの中でSystem.Environment.ProcessorCountの値を確認してみると1となっていたので、これは何か別の方法がありそうです。

おわりに

Blazor WebAssemblyでマルチスレッドを使うのは.NET 8を待つ必要がありますが、現時点で試せる範囲でマルチスレッドを動かしてみました。マルチコアを活用することも少しだけ体験できましたし、.NET 8を楽しみに待ちたいと思います。

8
5
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
8
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?