问题描述
|
这是一个控制台程序,要批量启动10个线程,等待5秒钟,然后批量停止。
static void Main(string[] args)
{
System.Threading.Tasks.Parallel.For(0,10,(index) =>
{
Action<int> act = (i) =>
{
Console.Write(\"start {0} \",i);
Thread.Sleep(5000);
};
act.BeginInvoke(index,OnTaskComplete,index);
});
Console.ReadKey();
}
static void OnTaskComplete(IAsyncResult res)
{
Console.Write(\"finish {0} \",res.AsyncState);
}
但是结果不是我所期望的,10个线程缓慢地(大约1秒间隔)一个接一个地启动,甚至在某些“启动”之前就出现了一些“完成”。
当注释掉Thread.Sleep时,所有线程都在Flash中开始和结束。
ѭ1影响其他线程吗?无论如何,有没有一个纯粹的空闲时间?
/ - - - - - - - - - - - - - - -编辑 - - - - - - - - - - ----------
同样的问题也发生在:
static void Main(string[] args)
{
System.Threading.Tasks.Parallel.For(0,(index) =>
{
Console.Write(\"start {0} \",index);
Thread.Sleep(5000);
Console.Write(\"fnish {0} \",index);
});
Console.ReadKey();
}
- - - - - - - - - - - 编辑 - - - - - - - - - - - -
终于我找到了一种替代thread.sleep的好方法
static void Main(string[] args)
{
System.Threading.Tasks.Parallel.For(0,index);
var t1 = new System.Threading.Timer(new TimerCallback(MyTimerCallback),index,5000,0);
});
Console.ReadKey();
}
static void MyTimerCallback(object o)
{
Console.Write(\"Timer callbacked \");
}
解决方法
这是设计使然。您会看到线程池管理器试图将有限数量的线程保持在执行状态。确保您的程序运行的线程数不超过计算机具有cpu内核的线程,这一点很重要。当Windows被迫开始在活动线程之间交换内核时,效率低下,工作量减少。线程池管理器不够聪明,无法知道线程正在休眠并且实际上没有执行任何工作。
在双核计算机上,您会立即看到前两个线程。然后,当线程管理器注意到活动线程没有取得任何进展并且可能被阻塞时,允许其他线程以一秒钟的间隔逐个运行。释放线程并执行Console.Write()调用的顺序不确定。
当然,这是一个人工测试,真实线程不会休眠。如果您有长时间阻塞的线程,例如,等待I / O请求完成,则使用线程池线程(任务)不是最佳解决方案。
,
TaskCreationOptions.LongRunning
将“删除” ThreadPool限制。
我不知道为Parallel.For
指定TaskCreationOptions.LongRunning
的简单方法。
但是,您可以使用Task类实现相同的效果:
Action<int> action = i =>
{
Console.Write(\"start {0} \",i);
Thread.Sleep(5000);
Console.Write(\"finish {0} \",i);
};
var tasks = Enumerable.Range(0,100)
.Select(arg => Task.Factory.StartNew(() => action(arg),TaskCreationOptions.LongRunning))
.ToArray();
Task.WaitAll(tasks);
如果没有TaskCreationOptions.LongRunning
,它将以与as6ѭ完全相同的方式运行。
, 我稍作更新了代码,以在写入控制台时显示ThreadID:
Console.WriteLine(\"start index:{0} thread id:{1} Time:{2} \",index,Thread.CurrentThread.ManagedThreadId.ToString(),DateTime.Now.ToLongTimeString());
Thread.Sleep(5000);
ConsoleWriteLine(\"finish index:{0} thread id:{1} Time:{2} \",DateTime.Now.ToLongTimeString());
我的机器是双核的,这是我得到的输出。这应该使您对正在发生的事情有所了解。请记住,循环可能并不总是按顺序运行,即0到9是并行的,它会抢占数组的一部分并通过lambda运行每一项。
输出:
start index:1 thread id:11 Time:11:07:17 PM
start index:0 thread id:9 Time:11:07:17 PM
start index:5 thread id:10 Time:11:07:17 PM
start index:6 thread id:12 Time:11:07:18 PM
start index:2 thread id:13 Time:11:07:19 PM
start index:7 thread id:14 Time:11:07:20 PM
start index:3 thread id:15 Time:11:07:21 PM
start index:8 thread id:16 Time:11:07:22 PM
finish index:0 thread id:9 Time:11:07:22 PM
start index:4 thread id:9 Time:11:07:22 PM
finish index:1 thread id:11 Time:11:07:22 PM
start index:9 thread id:11 Time:11:07:22 PM
finish index:5 thread id:10 Time:11:07:22 PM
finish index:6 thread id:12 Time:11:07:23 PM
finish index:2 thread id:13 Time:11:07:24 PM
finish index:7 thread id:14 Time:11:07:25 PM
finish index:3 thread id:15 Time:11:07:26 PM
finish index:8 thread id:16 Time:11:07:27 PM
finish index:4 thread id:9 Time:11:07:27 PM
finish index:9 thread id:11 Time:11:07:27 PM