1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

C#の非同期処理の味見

Posted at

経緯

製造現場で、外観検査機のデスクトップアプリを開発することになりました。このアプリでは以下のような3つの処理を行います。

📷 カメラ画像の取り込み
🧠 カメラ画像のAI判定
📊 レーザー変位計での寸法等測定とCSV出力

それぞれが独立した処理であり、1つ1つにそれなりの時間がかかります。最初は順番に実行しようと思いましたが、やはり時間がかかりすぎました。ChatGPTに聞いたところ「非同期処理を使え」と言われたので、初めてC#のasync / awaitを学ぶことになりました。

C#の非同期処理とは?

C#では、時間のかかる処理(I/Oや通信など)をメインスレッドを止めずに実行するためにasync / await構文が用意されています。

基本構文

static async Task Main()
{
    // 非同期処理を呼び出す
    await DoSomethingAsync();
}

static async Task DoSomethingAsync()
{
    Console.WriteLine("重い処理を開始...");
    
    // 非同期的に2秒待つ
    await Task.Delay(2000);
    
    Console.WriteLine("重い処理が完了!");
}

ポイント

async:メソッドが非同期であることを示す
await:処理の完了を「待つ」が、スレッドはブロックされない
Task:非同期処理の実行単位(戻り値を持つ場合は Task)

Step 1. 並行カウントで動作を可視化

並行でカウントする処理を作ってみました。
1つは1秒ごとに100回、もう1つは2秒ごとに30回カウントします。

using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        Console.WriteLine("処理開始");

        // 1秒間隔で100回カウントする非同期処理
        Task t1 = CountAsync("1秒カウント", 100, 1000);

        // 2秒間隔で30回カウントする非同期処理
        Task t2 = CountAsync("2秒カウント", 30, 2000);

        // 両方の処理が完了するまで待機
        await Task.WhenAll(t1, t2);

        Console.WriteLine("すべてのカウント完了!");
    }

    // 指定回数、指定間隔でカウントする非同期メソッド
    static async Task CountAsync(string name, int count, int intervalMs)
    {
        for (int i = 1; i <= count; i++)
        {
            Console.WriteLine($"{name}: {i}");
            // 非同期で待機、CPUは解放される
            await Task.Delay(intervalMs);
        }
        Console.WriteLine($"{name} 完了!");
    }
}

実行結果(抜粋)

処理開始
1秒カウント: 1
2秒カウント: 1
1秒カウント: 2
1秒カウント: 3
2秒カウント: 2
...
1秒カウント 完了!
2秒カウント 完了!
すべてのカウント完了!

await Task.WhenAll(...) により、2つの処理が完全に並行で動いていることが分かります。

Step 2. 3セット繰り返して確認する

次は、このカウント処理を3セット繰り返し、各セットごとに「ちゃんとカウントしたか確認」します。

using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        Console.WriteLine("処理開始");

        // 同じ処理を3回繰り返す
        for (int set = 1; set <= 3; set++)
        {
            Console.WriteLine($"\n==== 第{set}セット開始 ====");

            // 並行でカウント処理を開始
            Task<int> t1 = CountAsync("1秒カウント", 100, 1000);
            Task<int> t2 = CountAsync("2秒カウント", 30, 2000);

            // 両方の処理が完了するまで待つ
            int[] results = await Task.WhenAll(t1, t2);

            // 結果確認
            Console.WriteLine($"第{set}セット完了!確認:");
            Console.WriteLine($" - 1秒カウント 結果: {results[0]}回");
            Console.WriteLine($" - 2秒カウント 結果: {results[1]}回");
            Console.WriteLine("===========================");
        }

        Console.WriteLine("\nすべてのセット完了!");
    }

    // 指定回数、指定間隔でカウントする非同期メソッド(結果を返す)
    static async Task<int> CountAsync(string name, int count, int intervalMs)
    {
        for (int i = 1; i <= count; i++)
        {
            Console.WriteLine($"{name}: {i}");
            await Task.Delay(intervalMs); // 非同期で待機
        }

        Console.WriteLine($"{name} 完了!({count}回)");
        return count; // 完了した回数を返す
    }
}

出力イメージ

==== 第1セット開始 ====
1秒カウント: 1
2秒カウント: 1
...
1秒カウント 完了!(100回)
2秒カウント 完了!(30回)
第1セット完了!確認:
 - 1秒カウント 結果: 100回
 - 2秒カウント 結果: 30回
===========================

==== 第2セット開始 ====
...

すべてのセット完了!

まとめ

学んだこと 内容
async / await 非同期処理を直感的に書ける仕組み
Task 非同期処理の実行単位
Task.WhenAll() 複数の非同期処理を並行実行して待機
await Task.Delay() ブロックしない時間待ち
ループとの組み合わせ 非同期処理を順次制御する方法
1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?