有没有更好的方法来实现多线程?

时间:2019-07-05 08:15:53

标签: c# multithreading cpu-usage

下面的源代码部分使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
    }
}

1 个答案:

答案 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是基于任务的异步编程的一些示例。