任务中的秒表似乎是所有任务的附加,想要测量任务间隔
我正在循环运行并以下列方式启动任务:
var iResult = new List(); 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
的列表时, myMsg
似乎完全是加法的 – 第一个上的ElaspedMilliseconds可能是300,但最后一个可能是50000(50秒) – 这实际上是整个事情需要的大致时间运行(由另一个计时器测量)。
编辑:
哎呀,我也是第一次感到困惑。
问题是它只看起来很容易(累积),因为ElapsedTime值总是只按递增顺序输出。
所以,如果我在下面的演示中按顺序启动:
- 第一次启动任务的持续时间为10秒(10000毫秒),
- 第二个任务的持续时间为8秒(8 000毫秒),
- 3d任务的持续时间为6秒(6 000毫秒),
然后结果出现在初始顺序的输出中 – 总是按照任务持续时间的增加顺序:
- 输出中的第一个:3d启动任务的持续时间(持续时间为6秒)
- 输出中的第二个:第二个启动任务的持续时间(持续时间为8秒)
- 输出中的3d(最后一个):第一个启动任务的持续时间(持续时间为10秒)
以下是Console应用程序的输出:
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(); 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()
可能不是正确的multithreading,这意味着一个任务在第一个任务完成后运行,依此类推。 每个任务都有自己的计时器,它们都在大约同一时间开始(或者线程被分配给任务),但是长时间运行的任务会将它们全部抵消。
你永远不会有一个无限的线程池和任务处理谁获得一个线程和什么时候。
关于LongRunning:
“这不是一个特定的长度。如果你生成了很多任务,LongRunning就不适合他们。如果你生成一两个任务,相对于你的应用程序的生命周期会持续相当长的一段时间,然后LongRunning是需要考虑的事情。一般情况下,除非你发现你确实需要它,否则不要使用它。在幕后,它会导致使用更多的线程,因为它的目的是允许ThreadPool继续处理工作项,即使一个任务正在运行一段时间;如果该任务在池中的一个线程中运行,该线程将无法为其他任务提供服务。通常只使用LongRunning你通过性能测试发现,不使用它会导致其他工作处理的长时间延迟。“ – Stephen Toub