秒表在一个任务中似乎是加在所有任务上的,想要测量的只是任务间隔

本文关键字:任务 测量 一个 似乎是 | 更新日期: 2023-09-27 18:11:13

我正在一个循环中运行,并以以下方式启动任务:

var iResult = new List<Task>();
foreach(var i in myCollection)
{
    var task = Task.Factory.StartNew(() =>
                    DoSomething(), TaskCreationOptions.LongRunning);
    task.ContinueWith(m => myResponseHandler(m.Result));
    iResult.Add(task);
}

在我的DoSomething()方法,我有一个定时器:

public static myMsg DoSomething()
{
    var timer = System.Diagnostics.Stopwatch.StartNew();
    DoLongRunningTask(); //If it matters this hits a REST endpoint (https)
    timer.Stop();
    return new myMsg(timer.ElaspedMilliseconds);
}

当我迭代myMsg的列表时,ElaspedMilliseconds似乎是完全可加的-第一个的ElaspedMilliseconds可能是300,但最后一个可能是50000(50秒)-这实际上是整个事情运行所需的大约时间(由另一个计时器测量)。

秒表在一个任务中似乎是加在所有任务上的,想要测量的只是任务间隔

编辑:

哎呀,我一开始也很困惑。

问题在于它看起来只是相加的(累积的),因为ElapsedTime值总是只按递增顺序输出。

那么,如果我有,就像下面的演示一样,按照启动的顺序:

  • 第一个启动任务的持续时间为10秒(10000毫秒),
  • 第二个任务的持续时间为8秒(8000毫秒),
  • 3d任务的持续时间为6秒(6000毫秒),

则结果出现在输出中,不按初始顺序-总是按任务持续时间的增加顺序排列:

  • 第一个输出:3d启动任务的持续时间(6秒持续时间)
  • 第二个输出:第二个启动任务的持续时间(8秒持续时间)
  • 输出的3d(最后一个):第一个启动任务的持续时间(10秒持续时间)

下面是控制台应用程序的输出:

from DoSomething  6043  
from main  6043  
from DoSomething  8057  
from main  8057  
from DoSomething  10058
from main  10058

原因很明显——因为更快的任务总是在更长的(更耗时的)任务之前完成和输出。

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
      var iResult = new List<Task>();
      for (int i=5; i>2; i--)
      {
        int load = i;
        var task = Task.Factory.StartNew(() =>
                        DoSomething(load), TaskCreationOptions.LongRunning);
        //following commented lines do NOT change the behavior in question
        task.ContinueWith(m => Console.WriteLine("from main  "+m.Result));
        //iResult.Add(task);
      }
      Console.ReadLine();
    }
   //public static myMsg DoSomething()
    public static long DoSomething(int load)
    {
      Stopwatch timer = System.Diagnostics.Stopwatch.StartNew();
      //usage of either prev or following 2 lines produce the same results 
      //Stopwatch timer = new Stopwatch();  //instead of prev .StartNew();
      //timer.Start();// instead of prev .StartNew();
      Console.WriteLine("***Before calling  DoLongRunningTask()   " 
               + timer.ElapsedMilliseconds);
      Console.WriteLine("GetHashCode  "+timer.GetHashCode());
      DoLongRunningTask(load); 
      timer.Stop();
      long elapsed = timer.ElapsedMilliseconds;
      Console.WriteLine("from DoSomething  "+ elapsed);
      return elapsed;//return new myMsg(timer.ElaspedMilliseconds);
    }
    public static void DoLongRunningTask(int load)
    {
      Thread.Sleep(2000*load);
      /*******************  another variant of calculation intensive loading
             load = load;
             double result = 0;
             for (int i = 1; i < load*100000; i++)
                   result += Math.Exp(Math.Log(i) );
       */
    }
  }
}

最有可能发生的一件事是DoLongRunningTask()可能不是正确的多线程,这意味着一个任务在第一个任务完成后运行,等等。每个任务都有自己的计时器,它们都在同一时间(或者在为任务分配线程时)启动,但是长时间运行的任务会抵消它们。

你永远不会有一个无限的线程池和任务处理谁得到一个线程,什么时候。

关于龙润

:

"它本身并不是一个特定的长度。如果要生成很多任务,那么LongRunning不适合它们。如果要生成一两个相对于应用程序的生命周期而言将持续相当长时间的任务,那么可以考虑使用LongRunning。一般来说,除非你发现你真的需要它,否则不要使用它。在幕后,它将导致使用更多的线程,因为它的目的是允许ThreadPool继续处理工作项,即使一个任务运行了很长一段时间;如果该任务在池中的线程中运行,则该线程将无法为其他任务提供服务。如果您通过性能测试发现不使用LongRunning会导致处理其他工作的长时间延迟,那么您通常只会使用LongRunning。 - Stephen Toub