【问题标题】:Nested task inside loop循环内的嵌套任务
【发布时间】:2016-03-09 17:27:17
【问题描述】:

我正在尝试在循环中实现嵌套任务 - 这是我目前的模式,但我不确定,因为这是我第一次使用并行任务库。

父(层)任务应等待子(节点)任务完成。

    public int NestedTask(IEnumerable<MatchTier> tierNodes)
    {
        var tier = Task<int>.Factory.StartNew(() =>
        {
            Task<int> node = null;

            foreach(var n in tierNodes)
            {
                node = Task<int>.Factory.StartNew(() =>
                {
                    // Task logic goes here

                    return 1; // temp placeholder
                });

                // if a valid value is returned then exit this loop
            }

            return node.Result;

        });

        return tier.Result;
    }

子节点循环直到返回第一个有效值,然后应该退出循环,将有效值传递给父节点。

子节点和父节点都需要超时。每个子节点将被允许运行大约 3 秒,之后进程将超时并询问下一个节点。

父节点的总超时值约为 15 - 20 秒,在此之后,如果没有收到有效响应,它也应该终止。

这看起来合乎逻辑吗?

【问题讨论】:

  • 老实说,您只是在等待最后的结果并返回它。你真正想做什么?
  • 能否请您添加更多详细信息。 tierNodes 是您的父节点或子节点的集合?您如何从父节点获取子节点。我无法在代码中看到任何父子关系。更多信息会有所帮助
  • @Anand - 添加了更多详细信息。
  • 如果在方法结束时等待它的结果,为什么要使用任务tier?或者:为什么不直接使用内部循环创建Tasks?

标签: c# task


【解决方案1】:

等待任务完成做

node.Wait();

等待任务完成,直到一些滴答声完成

node.Wait(timeToWait);

或等待它们全部完成

Task.WaitAll(tasks);

你应该阅读here了解更多信息

【讨论】:

  • 我知道使用 parent.Result 会迫使父母等待。
【解决方案2】:

如上所述,task.Wait()task.Result(等待并获取结果)和Task.WaitAll(theTaskCollection) 是执行此操作的方法。我已经稍微改变了你的实现来解决这个问题,但我非常不确定你真正想要返回什么。我删除了外部任务,因为它似乎不需要。

public int NestedTask(IEnumerable<MatchTier> tierNodes)
{
  var tasks = tierNodes.Select(node => Task<int>.Factory.StartNew(() =>
            {
                // Task logic goes here
                return 1; // temp placeholder
            })).ToList(); // Enumerate to start tasks, not doing this would case WaitAll to start them one at a time (i believe)

  if (!Task.WaitAll(tasks, timeOutInMilliseconds))
    // Handle timeout...

  return tasks.First().Result; // Is this what you want?
}

编辑:添加修改后的解决方案。

public int NestedTask(IEnumerable<string> tierNodes)
{
  int parentTimeout = 15 * 1000;
  int childTimeout = 3 * 1000;

  var tier = Task<int>.Factory.StartNew(() =>
  {
      foreach (var n in tierNodes)
      {
          var node = Task<int>.Factory.StartNew(() =>
          {
              // Task logic goes here
              return 1;
          });

          // If we get the result we return it, else we wait
          if (node.Wait(childTimeout))
              return node.Result;
      }
      throw new Exception("did not get result!");
  });

  if (!tier.Wait(parentTimeout))
  {
      // The child will continue on running though.
      throw new TimeoutException("parent timed out");
  }
  else if (tier.Exception != null)
  {
      // We have an error
      throw tier.Exception.InnerException;
  }

  return tier.Result;
}

【讨论】:

  • 将需要外部任务,因为下一阶段将添加一些超时逻辑。但是,为了清楚起见,我没有这样做。
  • @dotnetnoob 为什么不在较低的任务级别设置超时?
  • 不同的超时将适用于每个节点 - 一个节点将有 3 秒的超时,而父层将有 15-20 秒的超时。每个节点在超时之前被允许运行指定的时间。测试下一个节点,依此类推,直到返回一个 calid 值或所有节点都用完。如果父节点发生超时,则放弃整个过程并测试下一层。
  • @dotnetnoob 我为您的新要求添加了一个新的解决方案。希望对你有帮助!
  • 谢谢 - 我会设置一些测试并尝试一下。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-08
  • 1970-01-01
  • 2016-05-13
相关资源
最近更新 更多