如何在.net 4.0中获取正在运行的任务列表

时间:2012-05-31 08:17:44

标签: c# task-parallel-library

我正在尝试获取所有当前正在运行的任务的列表。 .net 4.0任务API是否提供此类功能?或者唯一的选择是明确地将任务存储在单独的集合中?

5 个答案:

答案 0 :(得分:4)

我想你需要TaskScheduler.GetScheduledTasks方法,但是:

  1. 受保护
  2. MSDN说它应该只用于调试
  3. 据我所知,此方法仅由ThreadPoolTask​​Scheduler实现,SynchronizationContextTaskScheduler始终返回null
  4. 所以我认为你应该尝试实施own TaskScheduler来实现你的目标。

答案 1 :(得分:2)

创建任务时,默认情况下,任务计划在thread pool线程上运行。因此,您可以使用ThreadPool.GetMaxThreadsThreadPool.GetAvailableThreads方法获取正在运行的任务数。

    private static int GetWorkingThreads() {
        int maxThreads;
        int completionPortThreads;
        ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads);

        int availableThreads;
        ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads);

        return maxThreads - availableThreads;
    }

答案 2 :(得分:1)

为什么要查找正在运行的任务列表?除了调试之外,您不必使用此信息。在任何情况下,计划执行的任务列表与实际执行的任务之间存在差异。

正如Rusted所写,您可以从TaskScheduler.GetScheduledTasks方法获取预定任务的数量。该方法是抽象的,因此必须由所有TaskSchedulers实现。

实际执行的任务数取决于TaskScheduler实现。默认任务调度程序使用线程池,在这种情况下,您应检查ThreadPool.GetAvailableThreadsThreadPool.GetMaxThreads以估计执行任务的数量。

即使您使用默认的TaskScheduler,也没有正在运行的任务的实际列表。调度程序实质上将任务分配给ThreadPool并将实际执行留给池(实际上,它调用Task.ExecuteEntry私有方法)。它不需要保留正在运行的任务列表。

如果您希望将运行任务信息用于调试目的,则可以利用Event Trace for Windows events in TPL。遗憾的是,未记录任务已启动和任务已完成事件。我在使用dotPeek浏览Task.ExecuteEntry的定义时找到了它们。

我找到了一篇文章exploring the TPL events,但我不确定这是值得的。除非你正在编写自己的调试器,否则看起来太麻烦了。

如果你只需要进入正在运行的任务列表,也许你应该编写自己的TaskScheduler并覆盖TryExecute和TryExecuteInternal来拦截每个任务的执行并将每个任务放在一个列表中。这可能会变得昂贵,并且您必须定期进行一些清理以从列表中删除已完成的任务而不使用continuation(这将最终在列表中)。

答案 3 :(得分:0)

MSDN上有一篇很好的文章http://msdn.microsoft.com/en-us/library/ms997649.aspx 你所需要的一切都得到了很好的描述。

编辑: perhabs这将有所帮助:

using System;
using System.Diagnostics;

class MainClass
{
   public static void Main()
   {
      Process[] allProcs = Process.GetProcesses();

      foreach(Process proc in allProcs)
      {
         ProcessThreadCollection myThreads = proc.Threads;
         Console.WriteLine("process: {0},  id: {1}", proc.ProcessName, proc.Id);

         foreach(ProcessThread pt in myThreads)
         {
            Console.WriteLine("  thread:  {0}", pt.Id);
            Console.WriteLine("    started: {0}", pt.StartTime.ToString());
            Console.WriteLine("    CPU time: {0}", pt.TotalProcessorTime);
            Console.WriteLine("    priority: {0}", pt.BasePriority);
            Console.WriteLine("    thread state: {0}", pt.ThreadState.ToString()); 
         }
      }
   }
}

答案 4 :(得分:0)

@HelgeJensen在以下方面提出了可行的解决方案: How can I monitor the Task queues in the .NET TaskSchedulers (across AppDomain)

Microsoft不鼓励使用GetScheduledTasksForDebugger Method

此方法不是线程安全的,因此您不应同时使用它 与TaskScheduler的其他实例。从调用此方法 仅调试器,当调试器已暂停所有其他线程时。

我测试了提议的解决方案,并且即使在生产代码中使用该解决方案可能会导致崩溃的情况下,该解决方案仍然有效:

public static class ScheduledTaskAccess
{
    public static Task[] GetScheduledTasksForDebugger(TaskScheduler ts)
    {
        var mi = ts.GetType().GetMethod("GetScheduledTasksForDebugger", BindingFlags.NonPublic | BindingFlags.Instance);
        if (mi == null)
            return null;
        return (Task[])mi.Invoke(ts, new object[0]);
    }      
}

用法:

    Task[] tasks = GetScheduledTasksForDebugger(TaskScheduler.Current);
    int count = tasks.Length;

我们可以看到每个任务的状态: Obtained list of Tasks