C#で独自のタスクスケジューラを構築する方法

TPL(Task Parallel Library)は、.NET Framework 4.0で最初に導入された、最近のバージョンの.NETFrameworkで最も興味深い新機能の1つです。TPLを使用するには、System.Threading.Tasks名前空間を利用する必要があります。

タスクスケジューラとは何ですか?なぜそれらが必要なのですか?

では、タスクはどのようにスケジュールされていますか?さて、あなたのタスクをスケジュールする責任があるタスクスケジューラと呼ばれるコンポーネントがあります。本質的に、これはタスクをスレッドにキューイングできる低レベルのオブジェクトの抽象化です。

.NET Frameworkは、2つのタスクスケジューラを提供します。これには、.NET Frameworkスレッドプールで実行されるデフォルトのタスクスケジューラと、指定されたターゲットの同期コンテキストで実行される別のタスクスケジューラが含まれます。TPLのデフォルトのタスクスケジューラは、.NETFrameworkスレッドプールを利用していることに注意してください。このスレッドプールは、System.Threading.Tasks名前空間内に含まれるThreadPoolクラスによって表されます。

ほとんどの場合、デフォルトのタスクスケジューラで十分ですが、独自のカスタムタスクスケジューラを構築して、追加の機能、つまりデフォルトのタスクスケジューラでは提供されない機能を提供することもできます。このような機能には、FIFOの実行、同時実行の程度などが含まれます。

C#でTaskSchedulerクラスを拡張します

独自のカスタムタスクスケジューラを構築するには、System.Threading.Tasks.TaskSchedulerクラスを拡張するクラスを作成する必要があります。したがって、カスタムタスクスケジューラを構築するには、TaskScheduler抽象クラスを拡張し、次のメソッドをオーバーライドする必要があります。

  • QueueTaskはvoidを返し、パラメータとしてTaskオブジェクトを受け入れます。このメソッドは、タスクがスケジュールされるときに呼び出されます。
  • GetScheduledTasksは、スケジュールされたすべてのタスクのリスト(正確にはIEnumerable)を返します
  • TryExecuteTaskInlineは、タスクをインラインで、つまり現在のスレッドで実行するために使用されます。この場合、タスクはキューに入れる必要なしに実行されます。

次のコードスニペットは、TaskSchedulerクラスを拡張してC#でカスタムスケジューラを実装する方法を示しています。

パブリッククラスCustomTaskScheduler:TaskScheduler、IDisposable

    {{

    }

この記事の前半で説明したように、カスタムタスクスケジューラのGetScheduledTasks、QueueTask、およびTryExecuteTaskInlineメソッドをオーバーライドする必要があります。

パブリックシールクラスCustomTaskScheduler:TaskScheduler、IDisposable

  {{

        保護されたオーバーライドIEnumerableGetScheduledTasks()

        {{

            // TODO

        }

        保護されたオーバーライドvoidQueueTask(タスクタスク)

        {{

             // TODO

        }

        保護されたオーバーライドboolTryExecuteTaskInline(タスクタスク、bool taskWasPreviouslyQueued)

        {{

            // TODO

        }

        public void Dispose()

        {{

            // TODO

        }

  }

BlockingCollectionを使用して、タスクオブジェクトのコレクションをC#に保存します

それでは、カスタムタスクスケジューラの実装を始めましょう。次のコードスニペットは、BlockingCollectionを利用してタスクオブジェクトのコレクションを保存する方法を示しています。

パブリックシールクラスCustomTaskScheduler:TaskScheduler、IDisposable

 {{

        プライベートBlockingCollectiontasksCollection = new BlockingCollection();

        プライベート読み取り専用スレッドmainThread = null;

        public CustomTaskScheduler()

        {{

            mainThread = new Thread(new ThreadStart(Execute));

            if(!mainThread.IsAlive)

            {{

                mainThread.Start();

            }

        }

        private void Execute()

        {{

            foreach(tasksCollection.GetConsumingEnumerable()のvarタスク)

            {{

                TryExecuteTask(task);

            }

        } 

      //その他の方法

  }

CustomTaskSchedulerクラスのコンストラクターを参照してください。Executeメソッドの実行を開始するために、新しいスレッドがどのように作成および開始されたかに注意してください。

GetScheduledTasks、QueueTask、およびTryExecuteTaskInlineメソッドをC#で実装します

次に、カスタムタスクスケジューラでオーバーライドする必要がある3つのメソッドを実装する必要があります。これらの3つのメソッドには、GetScheduledTasks、QueueTask、およびTryExecuteTaskInlineが含まれます。

GetScheduledTasksメソッドは、タスクコレクションのインスタンスをIEnumerableとして返します。これは、Executeメソッドに示されているようにコレクションを列挙できるようにするために使用されます。QueueTaskメソッドは、Taskオブジェクトをパラメーターとして受け取り、それをタスクコレクションに格納します。TryExecuteTaskInlineメソッドには実装がありません—実装は読者に任せます。

保護されたオーバーライドIEnumerableGetScheduledTasks()

        {{

            tasksCollection.ToArray();を返します。

        }

        保護されたオーバーライドvoidQueueTask(タスクタスク)

        {{

            if(task!= null)

                TasksCollection.Add(task);

        }

        保護されたオーバーライドboolTryExecuteTaskInline(タスクタスク、bool taskWasPreviouslyQueued)

        {{

            falseを返します。

        }

C#でCustomTaskSchedulerの例を完了します

次のコードリストは、CustomTaskSchedulerの最終バージョンを示しています。

パブリックシールクラスCustomTaskScheduler:TaskScheduler、IDisposable

    {{

        プライベートBlockingCollectiontasksCollection = new BlockingCollection();

        プライベート読み取り専用スレッドmainThread = null;

        public CustomTaskScheduler()

        {{

            mainThread = new Thread(new ThreadStart(Execute));

            if(!mainThread.IsAlive)

            {{

                mainThread.Start();

            }

        }

        private void Execute()

        {{

            foreach(tasksCollection.GetConsumingEnumerable()のvarタスク)

            {{

                TryExecuteTask(task);

            }

        }

        保護されたオーバーライドIEnumerableGetScheduledTasks()

        {{

            tasksCollection.ToArray();を返します。

        }

        保護されたオーバーライドvoidQueueTask(タスクタスク)

        {{

            if(task!= null)

                TasksCollection.Add(task);           

        }

        保護されたオーバーライドboolTryExecuteTaskInline(タスクタスク、bool taskWasPreviouslyQueued)

        {{

            falseを返します。

        }

        private void Dispose(bool dispose)

        {{

            if(!disposed)return;

            タスクコレクション.CompleteAdding();

            tasksCollection.Dispose();

        }

        public void Dispose()

        {{

            Dispose(true);

            GC.SuppressFinalize(this);

        }

    }

実装したばかりのカスタムタスクスケジューラを使用するには、次のコードスニペットを使用できます。

CustomTaskScheduler taskScheduler = new CustomTaskScheduler();

Task.Factory.StartNew(()=> SomeMethod()、CancellationToken.None、TaskCreationOptions.None、taskScheduler);

C#でさらに多くのことを行う方法:

  • C#で抽象クラスとインターフェイスを使用する場合
  • C#でAutoMapperを操作する方法
  • C#でラムダ式を使用する方法
  • C#でAction、Func、およびPredicateデリゲートを操作する方法
  • C#でデリゲートを操作する方法
  • C#で簡単なロガーを実装する方法
  • C#で属性を操作する方法
  • C#でlog4netを操作する方法
  • C#でリポジトリデザインパターンを実装する方法
  • C#でリフレクションを操作する方法
  • C#でfilesystemwatcherを操作する方法
  • C#でレイジー初期化を実行する方法
  • C#でMSMを操作する方法
  • C#で拡張メソッドを操作する方法
  • C#でラムダ式を使用する方法
  • C#でvolatileキーワードを使用する場合
  • C#でyieldキーワードを使用する方法
  • C#でポリモーフィズムを実装する方法
  • C#で独自のタスクスケジューラを構築する方法
  • C#でRabbitMを操作する方法
  • C#でタプルを操作する方法
  • C#での仮想メソッドと抽象メソッドの調査