下面的源代码部分使CPU消耗很高!有没有更好的方法来实现多线程?
// This application will run 24 hours 7 days per week
// in server
static void Main(string[] args)
{
const int NUM = 10;
Thread[] t = new Thread[NUM];
for (int i = 0; i < t.Length; i++)
t[i] = new Thread(new ThreadStart(DoWork));
foreach (Thread u in t)
u.Start();
}
static void DoWork()
{
while (true)
{
// Perform scanning work
// If some conditions are satisfied,
// it will perform some actions
}
}
答案 0 :(得分:1)
如果不清楚while(true)
旋转循环中的内容,那么这个问题很难回答。如果您启动10个线程而每个线程都没有任何等待地旋转(使用诸如AutoResetEvent.WaitOne()
,Thread.Sleep()
等),则会消耗CPU,因为您要向CPU请求。>
为提高整体性能,如果不是绝对必要的,则线程不应旋转-在大多数情况下不是这样。线程应完成其工作,然后如果没有更多工作要做,则应入睡。仅当它们有更多工作项目要处理时,才应将它们唤醒。如果您的线程一直在运行-检查不时满足的某些条件,并且您有一种机制可以通知线程条件为真-那么自旋浪费了CPU循环。
从概念上讲,线程应该以这种方式工作。
while(true)
{
// Wait until a thread has something meaningful to do. Waiting can be done for instance by calling AutoResetEvent.WaitOne().
// Do a meaningful work here.
}
如果您以这种方式执行线程代码,则在线程等待时,它不会占用CPU,因此系统不会过度劳累,其他线程/进程也可以完成工作。
这里的主要问题是,如果您具有某种通知机制,当新工作项到达时,该通知机制可使您的线程唤醒。例如,大多数IO操作(例如TCP套接字,HTTP通信,从文件读取等)都支持异步通信,该异步通信允许线程仅在收到新数据时进入睡眠和唤醒状态。
另一方面,如果您没有这种机制-例如,您正在使用一个第三方库,该库在发生有意义的事情时不会通知您,则您必须进行某种旋转。但是即使是这种情况,问题仍然是,您需要多久检查一次是否满足条件-因此需要做一些工作。
如果说,如果满足条件,则仅需每秒检查一次,请将Thread.Sleep(1000)
调用添加到线程代码中。这将大大提高总体性能。甚至Thread.Sleep(0)
比无等待的旋转要好得多。
这里有一个重要说明。在现代C#中,不应将线程用作您的主要异步编程机制。使用class Task
使用基于任务的异步编程更容易实现,尤其是在使用await-async
C#关键字的情况下,并且在大多数情况下会带来更好的性能。
如果有太多的工作项无法使用当前的线程数进行处理,则任务会在内部使用线程创建新线程,如果没有足够的工作要做,则释放线程。最佳线程数减少了总内存消耗。
如今,几乎所有标准.NET API都支持基于任务的异步编程,因此,它是实现并行执行代码的主要工具。
Here是基于任务的异步编程的一些示例。