跟踪多步骤任务的进度

我正在开发一个向客户端公开Web服务的简单服务器。 某些请求可能需要很长时间才能完成,并且在逻辑上分为多个步骤。 对于此类请求,需要在执行期间报告进度。 此外,可以在前一个请求完成之前启动新请求,并且要求两个请求同时执行(禁止某些特定于系统的限制)。

我想让服务器将TaskId返回给它的客户端,并让客户端使用TaskId跟踪请求的进度。 我认为这是一个很好的方法,我留下了如何管理任务的问题。

从未使用过TPL,我认为这是解决这个问题的好方法。 实际上,它允许我同时运行多个任务,而无需手动管理线程。 我甚至可以使用ContinueWith相对容易地创建多步骤任务。

但是,我无法想出一种跟踪任务进度的好方法。 我意识到,当我的请求包含一个“步骤”时,该步骤必须合作报告其状态。 在这一点上,我宁愿避免这种情况。 但是,当请求包含多个步骤时,我想知道当前正在执行哪个步骤并相应地报告进度。 我能想到的唯一方法是非常无聊:

Task firstTask = new Task( () => { DoFirstStep(); return 3.14; } ); firstTask. ContinueWith( task => { UpdateProgress("50%"); return task.Result; } ). ContinueWith( task => { DoSecondStep(task.Result); return "blah"; }. ContinueWith( task => { UpdateProgress("100%"); return task.Result; } ). 

即使这并不完美,因为我希望Task能够存储自己的进度,而不是让UpdateProgress更新一些已知的位置。 此外,它还有一个明显的缺点,即在添加新步骤时必须更改很多地方(因为现在进度为33%,66%,100%而不是50%,100%)。

有没有人有一个好的解决方案?

谢谢!

这不是Task Parallel Library完全支持的场景。

您可能会考虑将进度更新提供给队列并在另一个任务上读取它们的方法:

 static void Main(string[] args) { Example(); } static BlockingCollection> _progressMessages = new BlockingCollection>(); public static void Example() { List> tasks = new List>(); for (int i = 0; i < 10; i++) tasks.Add(Task.Factory.StartNew((object state) => { int id = (int)state; DoFirstStep(id); _progressMessages.Add(new Tuple( id, 1, "10.0%")); DoSecondStep(id); _progressMessages.Add(new Tuple( id, 2, "50.0%")); // ... return 1; }, (object)i )); Task logger = Task.Factory.StartNew(() => { foreach (var m in _progressMessages.GetConsumingEnumerable()) Console.WriteLine("Task {0}: Step {1}, progress {2}.", m.Item1, m.Item2, m.Item3); }); List waitOn = new List(tasks.ToArray()); waitOn.Add(logger); Task.WaitAll(waitOn.ToArray()); Console.ReadLine(); } private static void DoSecondStep(int id) { Console.WriteLine("{0}: First step", id); } private static void DoFirstStep(int id) { Console.WriteLine("{0}: Second step", id); } 

此示例不显示您的任务可能长时间运行的要求的取消,error handling或帐户。 长时间运行的任务对调度程序提出了特殊要求。 有关这方面的更多讨论,请访问http://parallelpatterns.codeplex.com/ ,下载书籍草稿并查看第3章。

这只是在这种情况下使用任务并行库的方法。 TPL可能不是这里最好的方法。

如果您的Web服务在ASP.NET(或类似的Web应用程序服务器)中运行,那么您还应该考虑使用线程池中的线程执行任务而不是服务Web请求的可能影响:

Task Parallel Library如何在终端服务器或Web应用程序中扩展?

我认为您正在寻找的解决方案不会涉及Task API。 或者至少,不是直接的。 它不支持完成百分比的概念,并且Task / ContinueWith函数需要参与该逻辑,因为它的数据仅在该级别可用(只有最终调用ContinueWith才能知道完成的百分比,即便如此,以算法方式这样做也是最好的猜测,因为它当然不知道一个任务是否会比另一个任务花费更长的时间。我建议您创建自己的API来实现这一点,可能利用Task API做实际的工作。

这可能会有所帮助: http : //blog.stephencleary.com/2010/06/reporting-progress-from-tasks.html 。 除了报告进度外,此解决方案还支持更新表单控件,而不会使跨线程操作无效 。