20
19

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 5 years have passed since last update.

C# > Taskに引数を渡し復帰値を取得する

Last updated at Posted at 2016-01-04

#背景
Taskクラスには前から興味があったのですが、引数をどう渡せば良いのか分からなかったので、いろいろ調べて自分なりにサンプルを作成してみました。
参考になれば幸いです。
#サンプルについて
時間のかかる処理として素数の集合を求めるメソッドを用意し、それを同期で呼び出す方法と非同期(Task)で呼び出す方法を試してみました。そのメソッドには素数を求める為の最大の数、例えば100を指定したら0~100までの間にある素数の配列を返すようになっています。
#苦労した点
頭が悪いので、
return new Task<List<int>>(o => GetPrimes((int)o), n);
の一文を導き出すのに1週間掛かりました(笑)。
#第2版
laughterさん、chocolamintさん、ozwkさんから改善点や解説を頂きました。
本当に勉強になりました。本当にありがとうございました。
教えて頂いた事を踏まえて、備忘録としてサンプルを修正しました。
#サンプル (第2版)
GitHub TestPrime

Program.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;

namespace TestPrime
{
    class Program
    {
        static void Main(string[] args)
        {
            const int PrimesCount = 1000000;
            List<int> primes;
            Prime prime = new Prime();
            Stopwatch sw = new Stopwatch();

            // 同期で呼び出す
            sw.Reset();
            sw.Start();
            primes = prime.GetPrimes(PrimesCount);
            sw.Stop();
            Console.WriteLine("同期で呼び出す");
            Console.WriteLine($"{nameof(sw.Elapsed)} = {sw.Elapsed}");
            Console.WriteLine($"{nameof(primes.Count)} = {primes.Count}");
#if DEBUG
            Debug.WriteLine(string.Join(" ", primes.GetRange(0, 20)));
#endif

            // 同期で呼び出す
            sw.Reset();
            sw.Start();

            // 非同期はこの呼び方でもよいが....
            //Task<List<int>> task = prime.GetPrimesAsync(PrimesCount);
            //task.Start();

            // 利用する側(Programクラス)が非同期で呼び出す方が望ましい
            Task<List<int>> task = Task.Run(() => prime.GetPrimes(PrimesCount));

            sw.Stop();

            // タスクが終了するまで待つ。が...
            // task.ResultがWaitを兼ねている。
            // つまり、Resultを取得できるようになるまで待機する。
            //task.Wait();

            primes = task.Result;
            Console.WriteLine("\n非同期で呼び出す");
            Console.WriteLine($"{nameof(sw.Elapsed)} = {sw.Elapsed}");
            Console.WriteLine($"{nameof(primes.Count)} = {primes.Count}");

            Console.WriteLine("\n\nPush any key!");
            Console.ReadKey();
        }
    }
}
Prime.cs
using System.Collections.Generic;
using System.Threading.Tasks;

namespace TestPrime
{
    /// <summary>
    /// 素数を求めるクラス
    /// </summary>
    public class Prime
    {
        List<int> primes = new List<int>() { 2 };

        /// <summary>
        /// 引数 n までの素数を求める(同期型)
        /// </summary>
        /// <param name="n">求める素数の最大数</param>
        /// <returns>GetPrimesを実行するTask</returns>
        public Task<List<int>> GetPrimesAsync(int n)
        {
            // 引数を渡して復帰値を得るTaskを生成
            //return new Task<List<int>>(o => GetPrimes((int)o), n);

            // 上記よりシンプルな記述
            // 引数はnをキャプチャし使用している
            return new Task<List<int>>(() => GetPrimes(n));
        }

        /// <summary>
        /// 引数 n までの素数を求める(非同期型)
        /// </summary>
        /// <param name="n">求める素数の最大数</param>
        /// <returns>素数の配列</returns>
        public List<int> GetPrimes(int n)
        {
            for (int i = 2; i <= n; i++)
            {
                int primesCount = primes.Count;
                bool notPrimeFlag = false;
                for (int j = 0; j < primesCount; j++)
                {
                    if ((i % primes[j]) == 0)
                    {
                        notPrimeFlag = true;
                        j = primesCount;
                        break;
                    }
                }
                if (!notPrimeFlag)
                {
                    primes.Add(i);
                }
            }
            return primes;
        }
    }
}

#実行結果
コンソール
同期で呼び出す
Elapsed = 00:00:22.1918873
Count = 78498

非同期で呼び出す
Elapsed = 00:00:00.0004974
Count = 78498

Push any key!

[出力]ウィンドウ
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71

20
19
8

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
20
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?