2

私は現在プロジェクトに取り組んでおり、処理のためにいくつかのジョブをキューに入れる必要があります。要件は次のとおりです。

  1. ジョブは一度に1つずつ処理する必要があります
  2. キューに入れられたアイテムは、待機できる必要があります

だから私は次のようなものが欲しいです:

Task<result> QueueJob(params here)
{
   /// Queue the job and somehow return a waitable task that will wait until the queued job has been executed and return the result.
}

アイテムをキューから取り出してジョブを処理するだけのバックグラウンド実行タスクを試してみましたが、バックグラウンドタスクからメソッドに移行するのが困難です。

必要に応じて、QueueJobメソッドで完了コールバックを要求するだけのルートをたどることができますが、ジョブが処理されるのを待つことができる透過的なタスクを取り戻すことができれば素晴らしいと思います(ジョブがある場合でも)キューに入れる前)。

4

3 に答える 3

2

私は次のようなものに行きます:

class TaskProcessor<TResult>
{
    // TODO: Error handling!

    readonly BlockingCollection<Task<TResult>> blockingCollection = new BlockingCollection<Task<TResult>>(new ConcurrentQueue<Task<TResult>>());

    public Task<TResult> AddTask(Func<TResult> work)
    {
        var task = new Task<TResult>(work);
        blockingCollection.Add(task);
        return task; // give the task back to the caller so they can wait on it
    }

    public void CompleteAddingTasks()
    {
        blockingCollection.CompleteAdding();
    }

    public TaskProcessor()
    {
        ProcessQueue();
    }

    void ProcessQueue()
    {
        Task<TResult> task;
        while (blockingCollection.TryTake(out task))
        {
            task.Start();
            task.Wait(); // ensure this task finishes before we start a new one...
        }
    }
}

それを使用しているアプリの種類に応じて、BlockingCollection/ConcurrentQueue をより単純なもの (単純なキューなど) に切り替えることができます。キューに入れるメソッド/パラメーターの種類に応じて、「AddTask」メソッドのシグネチャを調整することもできます...

于 2013-02-18T05:48:34.807 に答える
1

Func<T>パラメータをとらず、型 T の値を返します。ジョブは 1 つずつ実行され、返されたタスクが結果を取得するのを待つことができます。

public class TaskQueue
{
    private Queue<Task> InnerTaskQueue;

    private bool IsJobRunning;

    public void Start()
    {
        Task.Factory.StartNew(() =>
        {
            while (true)
            {
                if (InnerTaskQueue.Count > 0 && !IsJobRunning)
                {
                     var task = InnerTaskQueue.Dequeue()
                     task.Start();
                     IsJobRunning = true;
                     task.ContinueWith(t => IsJobRunning = false);
                }
                else
                {
                     Thread.Sleep(1000);
                }
            }
        }
    }

    public Task<T> QueueJob(Func<T> job)
    {
        var task = new Task<T>(() => job());
        InnerTaskQueue.Enqueue(task);
        return task;
    }
}
于 2013-02-18T05:08:56.170 に答える