0

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

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

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

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

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

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

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

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

有没有办法在不编写自定义包装器的情况下做到这一点?使用线程池、任务、并行?

据我所知,并行阻塞线程直到任务完成,所以这不是一个优先行为。

正如我所见,创建任务时应该有没有参数的方法,所以这也不好。

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

当然,我可以制作自己的包装器,该包装器将使用 ThreadPool 实现所需的功能,但目标是在不编写此类的情况下实现这一点。

有人可以帮忙吗?谢谢。

4

3 回答 3

3

您正在寻找 TPL 和Task课程。

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

于 2013-03-03T20:05:58.410 回答
1

您正在寻找 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");
    }
}
于 2013-03-03T20:18:44.117 回答
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
}
于 2013-03-03T20:14:48.363 回答