【问题标题】:Run only the current task and the most recently queued task仅运行当前任务和最近排队的任务
【发布时间】:2014-02-10 17:26:54
【问题描述】:

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

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

【问题讨论】:

  • 禁用按钮怎么样?例如。任务启动后禁用TurnOn,直到它完成?
  • 这是一个操纵杆按钮,所以我不能完全禁用它。另外,我不想在我的代码中跳过任何状态转换。

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


【解决方案1】:

只需创建一个类来跟踪当前正在执行的任务、下一个要运行的动作,并且只要前一个动作完成就运行“下一个”动作。这里的关键是,如果下一个操作在您将新操作排入队列时具有值,您可以简单地替换 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);
    }
}

虽然您可以在此处接受未启动的任务,并且这样做是非常简单的重写,但我认为在这里接受委托并创建然后启动任务是更好的做法可以开始了。

【讨论】:

  • nextTask == null的情况下如何执行动作?
  • @Brannon 你是什么意思?如果下一个任务为空,它将给定项目设置为下一个任务,并在当前任务完成时创建一个继续运行它。
  • @Brannon 第一个版本处理了这个问题。更新后的代码只是确保如果一个操作被“跳过”,为它创建的任务被标记为“已取消”,而不是代表跳过它的操作的任务。
  • 我遇到了一些罕见的异常,其中currentlyExecuting = Task.Run(nextTask); 行中的nextTask 为空。你能看到任何可能发生的方式吗?
  • @Brannon 很确定我找到了。如果任务在启动后被取消,它将继续取消nextTask。我添加了检查以确保如果继续取消它不会这样做。
猜你喜欢
  • 2016-05-24
  • 1970-01-01
  • 1970-01-01
  • 2016-08-28
  • 1970-01-01
  • 1970-01-01
  • 2016-10-19
  • 1970-01-01
  • 2011-07-28
相关资源
最近更新 更多