本文介绍了跟踪多步骤任务的进度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am working on a simple server that exposes webservices to clients. Some of the requests may take a long time to complete, and are logically broken into multiple steps. For such requests, it is required to report progress during execution. In addition, a new request may be initiated before a previous one completes, and it is required that both execute concurrently (barring some system-specific limitations).

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

I was thinking of having the server return a TaskId to its clients, and having the clients track the progress of the requests using the TaskId. I think this is a good approach, and I am left with the issue of how tasks are managed.

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

Never having used the TPL, I was thinking it would be a good way to approach this problem. Indeed, it allows me to run multiple tasks concurrently without having to manually manage threads. I can even create multi-step tasks relatively easily using ContinueWith.

我不能想出一个很好的方法来跟踪任务的进度。我意识到,当我的请求包括单个步骤,那么步骤必须合作报告其状态。这是我想在这一点上避免的东西。但是,当请求由多个步骤组成时,我想知道当前正在执行的步骤,并相应地报告进度。我唯一可以想出的方法是非常令人讨厌:

I can't come up with a good way of tracking a task's progress, though. I realize that when my requests consist of a single "step", then the step has to cooperatively report its state. This is something I would prefer to avoid at this point. However, when a request consists of multiple steps, I would like to know which step is currently executing and report progress accordingly. The only way I could come up with is extremely tiresome:

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

甚至这不是完美的,因为我想任务存储自己的进度,而不是让UpdateProgress更新一些已知的位置。此外,它有明显的缺点,即在添加一个新的步骤(因为现在的进度是33%,66%,而不是50而改变很多地方%,100%)。

And even this is not perfect since I would like the Task to store its own progress, instead of having UpdateProgress update some known location. Plus it has the obvious downside of having to change a lot of places when adding a new step (since now the progress is 33%, 66%, 100% instead of 50%, 100%).

有人有好的解决方案吗?

Does anyone have a good solution?

谢谢! b $ b

推荐答案

这并不是Task Parallel Library完全支持的情况。

This isn't really a scenario that the Task Parallel Library supports that fully.

你可以考虑一种方法,你将进度更新提交到队列并在另一个任务上读取它们:

You might consider an approach where you fed progress updates to a queue and read them on another Task:

static void Main(string[] args)
{
    Example();
}

static BlockingCollection<Tuple<int, int, string>> _progressMessages =
    new BlockingCollection<Tuple<int, int, string>>();

public static void Example()
{
    List<Task<int>> tasks = new List<Task<int>>();

    for (int i = 0; i < 10; i++)
        tasks.Add(Task.Factory.StartNew((object state) =>
            {
                int id = (int)state;
                DoFirstStep(id);
                _progressMessages.Add(new Tuple<int, int, string>(
                    id, 1, "10.0%"));
                DoSecondStep(id);
                _progressMessages.Add(new Tuple<int, int, string>(
                    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<Task> waitOn = new List<Task>(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);
}

此示例不显示取消,错误处理或帐户,您的任务可能会长时间运行。长时间运行的任务对调度程序有特殊要求。有关这方面的更多讨论,请访问,下载图书草稿和请参阅第3章。

This sample doesn't show cancellation, error handling or account for your requirement that your task may be long running. Long running tasks place special requirements on the scheduler. More discussion of this can be found at http://parallelpatterns.codeplex.com/, download the book draft and look at Chapter 3.

这只是一种在这种情况下使用任务并行库的方法。

This is simply an approach for using the Task Parallel Library in a scenario like this. The TPL may well not be the best approach here.

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

If your web services are running inside ASP.NET (or a similar web application server) then you should also consider the likely impact of using threads from the thread pool to execute tasks, rather than service web requests:

这篇关于跟踪多步骤任务的进度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

06-29 08:59