C# 一个任务中的秒表似乎在所有任务中都是累加的,您只想测量任务间隔吗
我在循环中运行,并以以下方式启动任务:C# 一个任务中的秒表似乎在所有任务中都是累加的,您只想测量任务间隔吗,c#,synchronization,closures,task-parallel-library,stopwatch,C#,Synchronization,Closures,Task Parallel Library,Stopwatch,我在循环中运行,并以以下方式启动任务: var iResult = new List<Task>(); foreach(var i in myCollection) { var task = Task.Factory.StartNew(() => DoSomething(), TaskCreationOptions.LongRunning); task.ContinueWith(m => myResponseHand
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);
}
当我反复浏览我的
myMsg
列表时,elaspedmissions似乎是完全相加的-第一个列表上的elaspedmissions可能是300,但最后一个可能是50000(50秒)-这实际上是整个运行所需的大致时间(由另一个计时器测量)。每个任务都有自己的计时器,它们都是在大约相同的时间(或者当线程分配给任务时)的某个地方启动的,但是长时间运行的任务会将它们全部抵消
你永远不会有一个无限的线程池和任务句柄,谁获得了线程,何时获得
关于长跑:
“它本身并不是一个特定的长度。如果您正在生成大量任务,那么长时间运行不适合它们。如果生成一个或两个任务将持续相当长的时间,相对于应用程序的生命周期,那么LongRunning是值得考虑的。一般来说,除非你真的需要它,否则不要使用它。在幕后,它将导致使用更多的线程,因为它的目的是允许线程池继续处理工作项,即使一个任务运行了很长一段时间;如果该任务在池中的线程中运行,则该线程将无法服务于其他任务。如果通过性能测试发现不使用LongRunning会导致处理其他工作的长时间延迟,则通常只使用LongRunning。“-Stephen Toub编辑:
哎呀,我一开始也很困惑
问题在于,它看起来只是一个aditive(累加),因为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
原因很明显——因为更快的任务总是在更长(更耗时)的任务之前完成并输出
使用系统;
使用System.Collections.Generic;
使用系统线程;
使用System.Threading.Tasks;
使用系统诊断;
命名空间控制台应用程序1
{
班级计划
{
静态void Main(字符串[]参数)
{
var iResult=新列表();
对于(int i=5;i>2;i--)
{
int荷载=i;
var task=task.Factory.StartNew(()=>
DoSomething(加载)、TaskCreationOptions.LongRunning);
//以下注释行不会更改有问题的行为
task.ContinueWith(m=>Console.WriteLine(“from main”+m.Result));
//i结果添加(任务);
}
Console.ReadLine();
}
//公共静态myMsg DoSomething()
公共静态长剂量测量(内载)
{
秒表计时器=System.Diagnostics.Stopwatch.StartNew();
//使用prev或以下两行都会产生相同的结果
//秒表计时器=新秒表();//而不是上一个.StartNew();
//timer.Start();//而不是prev.StartNew();
Console.WriteLine(“***在调用DoLongRunningTask()之前”)
+计时器。延时毫秒);
WriteLine(“GetHashCode”+timer.GetHashCode());
多龙运行任务(load);
timer.Stop();
长时间运行=timer.elapsedmillisons;
控制台写入线(“从DoSomething”+经过);
return appeased;//返回新的myMsg(timer.elaspedmissions);
}
公共静态void DoLongRunningTask(int-load)
{
线程睡眠(2000*负载);
/*******************计算密集型负载的另一种变体
荷载=荷载;
双结果=0;
对于(int i=1;i
如果DoLongRUnningTask()
锁定共享数据段,很可能计时器的加法是正确的,因为每个计时器都会启动,然后暂停,直到前一个数据段完成。尝试用一个简单的延迟任务替换它,看看它是否计时正确。@Bobson,在任何共享图片上都没有任何锁定data@LightStriker,那么如果“DoLongRunningTask()
可能不是正确的多线程”,即使它正在重用同一个专用线程(这很可能是由于TaskCreationOptions.LongRunning
)?即使我显式创建了新实例Stopwatch timer=new Stopwatch()
或在使用前重置时间,计时器.elapsedmillesons
值是累积/递增到上一个实例您没有无限的线程数。代码不能也不会以无限并行方式运行。这取决于您的计算机、软件、操作系统、任务参数以及代码的运行方式一个线程被编译后,任务不太可能只共享一个线程,然后一个接一个地得到解决。每个任务可能会等待前一个任务完成。可以尝试的一件事是消除任务开销,直接运行线程。但是如果操作系统只为进程分配一个线程,则
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) );
*/
}
}
}