假设我们有一些方法可以做一些大的工作。
最初我们不知道有多少种方法(可以是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实现所需的功能,但目标是在不编写这样的程序的情况下进行此操作。
有人可以帮忙吗? 感谢。
答案 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
}