按顺序安排任务

时间:2014-03-31 12:57:31

标签: .net c#-4.0 scheduled-tasks c#-5.0

我的任务如下:

  1. 任务taskInput将数据输入inputQueue
  2. 任务taskOutput从inputQueue获取数据到outputQueue
  3. 从outputQueue消耗数据的并行任务
  4. 我想用以下条件运行任务:

      

    首先运行taskInput,taskOutput,最后运行Consumer。

    相应的代码:

                // Get data to inputQueue
                Task taskInput = new Task(()=>AddingItemToInputQueue());
                taskInput.Start();  
                // Grab data from inputQueue to outputQueue.
                Task taskOutput = new Task(() => AddItemToOutputQueue());
                taskOutput.Start();
    
                // Parallel tasks for consume data from outputQueue
                int threadCount = n;
                Task[] workers = new Task[threadCount];
                for (int i = 0; i < threadCount; ++i)
                {
                    Task task=Task.Run(()=>Consumer(i));
                    workers[i] = task;
                }
                Task.WaitAll(workers);
    

    关于inputQueue和outputQueue:

        BlockingCollection<Messages> InputQueue = new BlockingCollection<Messages>();
        BlockingCollection<Messages> OutputQueue = new BlockingCollection<Messages>();
    

    我的问题:

    1. 安排任务。我以为我们可以使用Task.ContinueWith方法机器人不知道如何将它应用到Consumer
    2. 我不确定它是否是线程安全的,因为在运行Consumer时可能会将新项目添加到inputQueue。

2 个答案:

答案 0 :(得分:1)

您可以尝试启动第一个任务(taskInput),当它完成后,继续执行第二个任务(taskOutput),除非必须并行工作。在这种情况下,您必须单独启动,因为您已经在做。

Task.Run(() => AddingItemToInputQueue())
            .ContinueWith(task => AddItemToOutputQueue());

并行地,从outputQueue

开始使用消费数据的任务
// Parallel tasks for consume data from outputQueue
int threadCount = n;
Task[] workers = new Task[threadCount];
for (int i = 0; i < threadCount; ++i)
{
    Task task = Task.Run(() => Consumer(i));
    workers[i] = task;
}
Task.WaitAll(workers);

或者你可以试试这样的事情:

Task.Run(() => AddingItemToInputQueue())
    .ContinueWith(x => AddItemToOutputQueue())
    .ContinueWith(t =>
    {
        int threadCount = n;
        Task[] workers = new Task[threadCount];
        for (int i = 0; i < threadCount; ++i)
        {
            Task task = Task.Run(() => Consumer(i));
            workers[i] = task;
        }
        Task.WaitAll(workers);
    });

在这种情况下,它会按您的意愿运行:首先taskInput,然后是taskOutput,最后是Consumer

BlockingCollection是线程安全的,因此您可以在多任务中添加和删除数据,它将在必要时管理自身阻止。

您可以查看有关Task.Factory.StartNewTask.Run here

的详情

答案 1 :(得分:0)

使用async-await,您可以这样写:

async Task DoStuffAsync()
{
    // Get data to inputQueue
    await Task.Run(()=>AddingItemToInputQueue());

    // Grab data from inputQueue to outputQueue.
    await Task.Run(() => AddItemToOutputQueue());

    // Parallel tasks for consume data from outputQueue
    int threadCount = n;
    Task[] workers = new Task[threadCount];
    for (int i = 0; i < threadCount; ++i)
    {
        Task task=Task.Run(()=>Consumer(i));
        workers[i] = task;
    }

    await Task.WhenAll(workers);
}

但是,由于您需要将AddingItemToInputQueueAddItemToOutputQueueTask包装在一起以使它们异步,因此您只需增加开销。同样适用于Consumer

你不妨这样做:

void DoStuff()
{
    // Get data to inputQueue
    AddingItemToInputQueue();

    // Grab data from inputQueue to outputQueue.
    AddItemToOutputQueue();

    // Parallel tasks for consume data from outputQueue
    int threadCount = n;
    Parallel.For(0, n, i => Consumer(i));
}