仅运行当前任务和最近排队的任务

时间:2014-02-10 17:26:54

标签: c# .net multithreading task-parallel-library

我有一些方法。我们称之为“TurnOn”和“TurnOff”。每个都返回一个未启动的任务(如在System.Threading.Tasks.Task中)。一旦启动,该任务大约需要一秒钟才能完成。我有一些代码用Task.ContinueWith方法对它们进行排队(显示为here)。问题是我只想要当前正在运行的任务(如果有的话)加上最近请求的任务来运行。目前,如果我的用户在一秒内切换开/关开关十次,我的代码需要花费二十秒来赶上。这只是我关心的最终要求。我怎样才能做到这一点?我无法在ContinueWith方法中看到一种方法来知道它之后是否还有另一个ContinueWith方法。我一直在查看示例here,但看不清楚如何应用它。

更新:现在可以在此库中找到它:https://github.com/BrannonKing/Kts.ActorsLite。它被命名为“MostRecent ...”

1 个答案:

答案 0 :(得分:3)

只需创建一个跟踪当前正在执行的任务的类,下一个要运行的操作,并在上一个操作完成时运行“下一个”操作。这里的关键是,如果下一个操作在您排队新值时有值,则只需替换nextTask而不是添加另一个延续。

public class TaskQueue
{
    private Task currentlyExecuting = Task.FromResult(false);
    public Task continuation = null;
    private CancellationTokenSource cts = new CancellationTokenSource();
    private Action nextTask = null;
    private object key = new object();
    public Task Queue(Action action)
    {
        lock (key)
        {
            if (nextTask == null)
            {
                nextTask = action;
                ScheduleContinuation();
                return continuation;
            }
            else
            {
                cts.Cancel();
                nextTask = action;
                ScheduleContinuation();
                return continuation;
            }
        }
    }

    private void ScheduleContinuation()
    {
        cts = new CancellationTokenSource();
        var token = cts.Token;
        continuation = currentlyExecuting.ContinueWith(t =>
        {
            lock (key)
            {
                currentlyExecuting = Task.Run(nextTask);
                token.ThrowIfCancellationRequested();
                nextTask = null;
            }
        }, cts.Token);
    }
}

虽然你可以接受这里的未启动任务,并且这是一个非常简单的重写,但我认为这里更好的做法是接受一个委托并创建然后启动它的任务准备开始了。