45

以下のようなコードは、ジョブを実行するための新しいスレッドを開始します。そのスレッドの優先度を制御する方法はありますか?

Task.Factory.StartNew(() => {
    // everything here will be executed in a new thread.
    // I want to set the priority of this thread to BelowNormal
});
4

4 に答える 4

60

他の人が述べているように、タスクを実行するにはカスタムスケジューラを指定する必要があります。残念ながら、適切な組み込みスケジューラはありません。

GlennがリンクしているParallelExtensionsExtrasを使用することもできますが、コードに直接貼り付けることができる単純なものが必要な場合は、次のことを試してください。このように使用します:

Task.Factory.StartNew(() => {
    // everything here will be executed in a thread whose priority is BelowNormal
}, null, TaskCreationOptions.None, PriorityScheduler.BelowNormal);

コード:

public class PriorityScheduler : TaskScheduler
{
    public static PriorityScheduler AboveNormal = new PriorityScheduler(ThreadPriority.AboveNormal);
    public static PriorityScheduler BelowNormal = new PriorityScheduler(ThreadPriority.BelowNormal);
    public static PriorityScheduler Lowest = new PriorityScheduler(ThreadPriority.Lowest);

    private BlockingCollection<Task> _tasks = new BlockingCollection<Task>();
    private Thread[] _threads;
    private ThreadPriority _priority;
    private readonly int _maximumConcurrencyLevel = Math.Max(1, Environment.ProcessorCount);

    public PriorityScheduler(ThreadPriority priority)
    {
        _priority = priority;
    }

    public override int MaximumConcurrencyLevel
    {
        get { return _maximumConcurrencyLevel; }
    }

    protected override IEnumerable<Task> GetScheduledTasks()
    {
        return _tasks;
    }

    protected override void QueueTask(Task task)
    {
        _tasks.Add(task);

        if (_threads == null)
        {
            _threads = new Thread[_maximumConcurrencyLevel];
            for (int i = 0; i < _threads.Length; i++)
            {
                int local = i;
                _threads[i] = new Thread(() =>
                {
                    foreach (Task t in _tasks.GetConsumingEnumerable())
                        base.TryExecuteTask(t);
                });
                _threads[i].Name = $"PriorityScheduler: {i}";
                _threads[i].Priority = _priority;
                _threads[i].IsBackground = true;
                _threads[i].Start();
            }
        }
    }

    protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
    {
        return false; // we might not want to execute task that should schedule as high or low priority inline
    }
}

ノート:

  • ワーカースレッドはすべてバックグラウンドスレッドであるため、このスケジューラーを使用して重要なタスクをスケジュールしないでください。プロセスがシャットダウンした場合に破棄できるもののみ
  • BnayaEshetによる実装から適応
  • 私はすべてのオーバーライドを完全に理解しているわけではありません。MaximumConcurrencyLevel、、GetScheduledTasksおよびのBnayaの選択をそのまま使用しTryExecuteTaskInlineます。
于 2012-01-29T20:56:47.527 に答える
20

タスクのスレッド優先度は、タスクを実行する実際のメソッド内で設定できます。ただし、問題を回避するために、完了したら優先度を復元することを忘れないでください。

したがって、最初にタスクを開始します。

new TaskFactory().StartNew(StartTaskMethod);

次に、スレッドの優先度を設定します。

void StartTaskMethod()
{
    try
    {
        // Change the thread priority to the one required.
        Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;

        // Execute the task logic.
        DoSomething();
    }
    finally
    {
        // Restore the thread default priority.
        Thread.CurrentThread.Priority = ThreadPriority.Normal;
    }
}

優先度を変更するときは、次の点に注意してください。ThreadPool(またはタスク)スレッドの優先度を変更しないのはなぜですか?

于 2012-01-09T16:22:12.653 に答える
11

これは、スレッドプールを使用するかどうかを決定する際の「すべきでないこと」の1つです;-)

詳細はこちら: http: //msdn.microsoft.com/en-us/library/0ka9477y.aspx

したがって、答えは「いいえ、Theadsプールで作成されたスレッドに特定の優先順位を指定することはできません」です。

一般的なスレッドに関しては、 Thread.Priorityプロパティについてはすでにご存知だと思います。

于 2010-10-01T04:52:26.047 に答える
8

で優先度を設定するには、このMSDNブログ投稿でMicrosoftの専門家であるStephenToubTaskが説明しているカスタムタスクスケジューラを確認してください。詳細については、彼が最初の文で言及している前の2つの投稿へのリンクをお見逃しなく。

あなたの問題については、あなたが見たいと思うかもしれないように聞こえますQueuedTaskScheduler

于 2010-11-16T05:47:32.447 に答える