使用回调对多个任务进行排队

时间:2013-03-03 20:01:56

标签: c# multithreading task-parallel-library threadpool

假设我们有一些方法可以做一些大的工作。

最初我们不知道有多少种方法(可以是1,可以是10)。

在代码中,这看起来像这样:

public interface IWorker
{
    void DoWork(DataContainer data);
}

实现此接口的几个类。 然后我们有实例列表。

List<IWorker> workers = new List<IWorker>();

我想异步运行这些方法。另外,当所有这些都被执行时,我想要一些回调。

public void Callback()
{
    Console.WriteLine("everything done");
}

有没有办法在不编写自定义包装器的情况下执行此操作?使用ThreadPool,Tasks,Parallel?

据我所知,Parrallel块线程直到任务完成,所以这不是一个预先设定的行为。

在创建Task时,应该有没有参数的方法,因为我看到这样做也不好。

在ThreadPool中有可能使用方法QueueUserWorkItem,但是使用这种方法我不会得到一个“完全完成”回调。

当然,我可以创建自己的包装程序,使用ThreadPool实现所需的功能,但目标是在不编写这样的程序的情况下进行此操作。

有人可以帮忙吗? 感谢。

3 个答案:

答案 0 :(得分:3)

您正在寻找TPL和Task类。

为每个操作创建Task,然后调用Task.WhenAll以获取聚合任务

答案 1 :(得分:2)

你正在寻找Task.WhenAll。创建一堆执行您想要的任务,然后等待所有任务并继续回调。我拆分了DoWork方法的异步版本 - 如果你总是以异步方式调用它,那么你不一定需要这样做。

public interface IWorker
{
    Task DoWorkAsync(string data);
    void DoWork(string data);
}

public class Worker : IWorker
{
    public Task DoWorkAsync(string data)
    {
        return Task.Run(() => DoWork(data));
    }

    public void DoWork(string data)
    {
        Console.WriteLine(data);
        Thread.Sleep(100);
    }
}

public class Runner
{
    public void Callback()
    {
        Console.WriteLine("Everything done");
    }

    public void Run()
    {
        var workers = new List<IWorker> {new Worker(), new Worker(), new Worker()};
        var tasks = workers.Select(t => t.DoWorkAsync("some data"));

        Task.WhenAll(tasks).ContinueWith(task => Callback());

        Console.WriteLine("Waiting");
    }
}

答案 2 :(得分:0)

听起来像CountdownEvent班的主要候选人:

List<IWorker> workers = new List<IWorker>();
using (CountdownEvent e = new CountdownEvent(workers.Count))
{
    foreach (IWorker worker in workers)
    {
        // Dynamically increment signal count.
        e.AddCount();
        // run work itself on another thread
        ThreadPool.QueueUserWorkItem(delegate(object state)
        {
            try
            {
                ((IWorker)state[0]).DoWork((DataContainer)state[1]);
            }
            finally
            {
                e.Signal();
            }
        },
        // pass required parameters for block of work
        new object[] { worker, dataForWorker });
    }

    // wait for all workers to finish
    e.Wait();
    // run callback code
}