9

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

4

5 回答 5

5

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

  1. 它受到保护
  2. MSDN 说它应该只用于调试
  3. 据我所知,此方法仅由 ThreadPoolTask​​Scheduler 实现,SynchronizationContextTaskScheduler 始终返回 null

所以我认为你应该尝试实现自己的 TaskScheduler来实现你的目标。

于 2012-05-31T12:52:47.053 回答
2

创建任务时,默认情况下该任务被安排在线程池线程上运行。因此,您可以使用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;
    }
于 2012-05-31T09:54:52.870 回答
1

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

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

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

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

如果您希望运行任务信息用于调试目的,您可以利用TPL 中的 Windows 事件的事件跟踪。不幸的是,没有记录 Task Started 和 Task Finished 事件。我在使用 dotPeek 浏览 Task.ExecuteEntry 的定义时发现了它们。

我找到了一篇探索 TPL 事件的文章,但我不确定这是否值得。除非你自己写调试器,否则似乎太麻烦了。

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

于 2012-06-01T08:09:10.117 回答
0

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

编辑:也许这会有所帮助:

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()); 
         }
      }
   }
}
于 2012-05-31T08:23:19.940 回答
0

@HelgeJensen 提出了一个可行的解决方案: 如何监控 .NET TaskSchedulers 中的任务队列(跨 AppDomain)

Microsoft 不鼓励使用GetScheduledTasksForDebugger 方法

此方法不是线程安全的,您不应将它与其他 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;

我们可以看到每个任务的状态: 获得的任务列表

于 2020-01-22T10:04:50.723 回答