Taskには、作成時にTaskCreationOptionsを指定することができます。
その中に、
TaskCreationOptions.LongRunning
という項目があります。文字通り長時間処理されるタスクの場合に
指定する項目なのですが、これを指定すると場合によっては、タスクスケジューラが
スレッドプールスレッドを利用せずにタスクを実行することがあります。
- TaskCreationOptions 列挙体
あまり利用する事はありませんが、サンプル作ったのでついでなのでアップしました。
以下、サンプルです。
namespace Sazare.Samples { using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Sazare.Common; /// <summary> /// タスク並列ライブラリについてのサンプルです。 /// </summary> /// <remarks> /// タスク並列ライブラリは、.NET 4.0から追加されたライブラリです。 /// </remarks> [Sample] class TaskSamples06 : IExecutable { public void Execute() { // // タスクには作成時にTaskCreationOptionsを // 指定することができる。このオプションの中に // TaskCreationOptions.LongRunning // という項目がある。LongRunningを指定すると // このタスクは、通常よりも長い間処理が続く // ということをタスクスケジューラに通知することに // なる。 // // LongRunningと指定されたタスクは場合によって // スレッドプールスレッドを利用せずに実行される。 // (長時間の処理で、かつ、ブロックする場合など) // // LongRunningを指定するとタスクスケジューラに対して // オーバーサブスクリプションを許可することになる。 // // なので、一つや二つなどの場合はいいが // たくさんのタスクをLongRunningさせるべきではない。 // (長時間かかる処理を producer/consumerパターンを // 利用して実装するなどの工夫が必要。) // // // 処理前のスレッドプールのスレッド数を表示. // Output.WriteLine("Before Task running..."); PrintAvailableThreadPoolCount(); // // 通常のタスクを開始し、その後スレッド数を表示. // var task1StartSignal = new ManualResetEventSlim(false); var task1 = Task.Run(() => { task1StartSignal.Set(); Output.WriteLine("Normal Task..."); SpinWait.SpinUntil(() => false, 5000); } ); task1StartSignal.Wait(); Output.WriteLine("After Task running..."); PrintAvailableThreadPoolCount(); // // TaskCreationOptions.LongRunningを // 指定して、タスクを開始. // (TaskCreationOptionsはTask.Runメソッドで指定できないので注意) // var task2StartSignal = new ManualResetEventSlim(false); var task2 = Task.Factory.StartNew(() => { task2StartSignal.Set(); Output.WriteLine("LongRunning Task...."); SpinWait.SpinUntil(() => false, 5000); }, TaskCreationOptions.LongRunning ); task2StartSignal.Wait(); Output.WriteLine("After LongRunning Task running..."); PrintAvailableThreadPoolCount(); // // 終了待ち. // Task.WaitAll(task1, task2); } internal void PrintAvailableThreadPoolCount() { int availableWorkerThreadsCount; int availableIOThreadsCount; ThreadPool.GetAvailableThreads( out availableWorkerThreadsCount, out availableIOThreadsCount); Output.WriteLine( string.Format( "\tWorker Threads: {0}, IO Threads: {1}", availableWorkerThreadsCount, availableIOThreadsCount)); } } }
実行結果は、以下のようになります。
================== START ================== Before Task running... Worker Threads: 1023, IO Threads: 1000 Normal Task... After Task running... Worker Threads: 1022, IO Threads: 1000 LongRunning Task.... After LongRunning Task running... Worker Threads: 1022, IO Threads: 1000 ================== END ==================
結果をみると、通常のタスクが実行されるとスレッドプールのスレッド数が 一つ減っているのに対して、LongRunningを指定して実行した場合 数が減っていません。(常にこうなるとは限りませんのでご注意を)
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ
サンプルコードは、以下の場所で公開しています。
- いろいろ備忘録日記サンプルソース置き場