线程优先级(如何获得固定订单)

时间:2011-12-30 19:15:05

标签: c# multithreading

在控制台中

因为线程与random一起睡觉,它将显示线程的顺序 3,2,1或1,2,3或...... 我怎么能有固定的订单? 为什么当我设置优先级它不会影响代码?       // ThreadTester.cs         //多个线程以不同的间隔打印。

    using System;
    using System.Threading;

    namespace threadTester
    {
        // class ThreadTester demonstrates basic threading concepts
        class ThreadTester
        {
            static void Main(string[] args)
            {
                // Create and name each thread. Use MessagePrinter's
                // Print method as argument to ThreadStart delegate.
                MessagePrinter printer1 = new MessagePrinter();
                Thread thread1 =
                   new Thread(new ThreadStart(printer1.Print));
                thread1.Name = "thread1";

                MessagePrinter printer2 = new MessagePrinter();
                Thread thread2 =
                   new Thread(new ThreadStart(printer2.Print));
                thread2.Name = "thread2";

                MessagePrinter printer3 = new MessagePrinter();
                Thread thread3 =
                   new Thread(new ThreadStart(printer3.Print));
                thread3.Name = "thread3";

                Console.WriteLine("Starting threads");

                // call each thread's Start method to place each 
                // thread in Started state
                thread1.Priority = ThreadPriority.Lowest;
                thread2.Priority = ThreadPriority.Normal;
                thread3.Priority = ThreadPriority.Highest;
                thread1.Start();
                thread2.Start();
                thread3.Start();

                Console.WriteLine("Threads started\n");
                Console.ReadLine();

            } // end method Main

        } // end class ThreadTester

        // Print method of this class used to control threads
        class MessagePrinter
        {
            private int sleepTime;
            private static Random random = new Random();

            // constructor to initialize a MessagePrinter object
            public MessagePrinter()
            {
                // pick random sleep time between 0 and 5 seconds
                sleepTime = random.Next(5001);
            }

            // method Print controls thread that prints messages
            public void Print()
            {
                // obtain reference to currently executing thread
                Thread current = Thread.CurrentThread;

                // put thread to sleep for sleepTime amount of time
                Console.WriteLine(
                   current.Name + " going to sleep for " + sleepTime);

                Thread.Sleep(sleepTime);

                // print thread name
                Console.WriteLine(current.Name + " done sleeping");

            } // end method Print

        } // end class MessagePrinter
    }

5 个答案:

答案 0 :(得分:2)

你精确地使用线程是因为你不关心按特定顺序发生事情,但是想要:

  1. 同时,如果有足够的核心允许它们一起发生。
  2. 有些人正在等待某些事情取得进展。
  3. 交互式注意I / O或用户输入,以便继续做出响应。
  4. 在每一种情况下,你都不在乎你不知道在什么时候会发生什么。

    然而:

    1. 您可能仍然关心某些序列的顺序。在最简单的情况下,你只需要在同一个线程中按顺序发生这些事情,而其他事情则发生在其他线程中。通过将任务链接在一起可以提供更复杂的案例。
    2. 您可能希望最终将不同线程的结果放入不同的顺序。最简单的方法是在它们全部完成之后将它们全部按顺序排列,尽管你也可以在它们到来时对结果进行排序(虽然很棘手)。
    3. 为了获得理想的性能,每个核心上应该有一个线程运行(或者在超线程核心上可能有两个线程,但这有更多的复杂性)。让我们假设您拥有一台拥有4个核心和8个任务的计算机。

      如果任务涉及大量等待I / O,那么将启动四个,每个任务将达到等待I / O的点,并允许其他任务之一取得一些进展。有可能即使任务数量是核心数量的两倍,它仍然会有足够的空闲时间。如果每个任务都需要20秒,那么在不同的线程上执行它们可能会在20秒内完成它们,因为所有这些都花费了20秒的大部分时间等待其他事情。

      如果你正在做的任务一直让CPU保持忙碌(没有多少等待内存,当然也没有等待I / O)那么你一次可以有四个这样的任务,而其他人正在等待让他们要么完成,要么放弃他们的时间。在这里,如果每个花费20秒,你可以期望的最好的是大约40秒的总时间(并且假设系统上的任何进程中没有其他线程想要CPU,那么你完全没有设置线程的开销等)。

      如果还有更多的工作要做(主动工作要做,而不是等待I / O完成,另一个线程要释放锁等),那么操作系统调度程序将在不同的线程之间交换想要活跃的。确切的细节因操作系统而异(不同的Windows版本,包括桌面和服务器设置之间的一些重要差异,采用不同的方法,不同的Linux版本,从2.4到2.6和不同的Unix等一些特别大的变化,等都有不同的策略)。

      他们都有一个共同点,那就是确保完成工作的共同目标。

      线程优先级和进程优先级是影响此调度的方法。使用Windows,只要有更多的线程等待工作而不是内核工作,那些具有最高优先级的线程就会以循环方式获得给定的CPU时间。如果没有该优先级的线程,则下一个最低线程的线程将获得CPU时间,然后是下一个线程,依此类推。

      这是让事情陷入停顿的好方法。它可能导致并发症,其中一个被赋予高优先级的线程(可能是因为它的工作被认为是特别重要的)正在等待给予低优先级的线程(可能是因为它的工作被认为不那么重要而且总是希望它总是等待其他人的时间),并且低优先级线程不会给予CPU时间,因为总是有比可用核心更高优先级的线程。因此,所谓的高优先级线程根本没有CPU时间。

      为了解决这种情况,Windows偶尔会推广那些在很长一段时间内无法运行的线程。这解决了问题,但现在意味着你已经将所谓的低优先级线程作为超高优先级突破,不仅损害了应用程序的其余部分,还损害了系统的其余部分。

      (拥有多核系统最好的事情之一,是否意味着您的计算体验受到设置线程优先级的人的影响较小!)

      如果您使用调试器来停止多线程.NET应用程序并检查线程,您可能会发现所有线程都处于正常状态,除了最高级别的线程。最高级别的这个将是终结器线程,并且它以最高优先级运行是终结器不应该花费很长时间执行的重要原因之一 - 以最高优先级完成工作是一件坏事,虽然它是合理的必须尽快结束。

      在有人设置线程优先级的所有其他情况中,至少95%是一个逻辑错误 - 它在大多数情况下都不会做任何事情,并且让事情变得非常混乱。它们可以很好地使用(或者我们根本不具备这种能力),但绝对应该采用先进的技术和#34;类别。 (我喜欢花费我的空闲时间来尝试多线程技术,这些技术在大多数情况下会被认为是过度和过早的优化,而且我仍然几乎没有触及优先级。)

      在你的例子中,优先级几乎没有效果,因为每个线程大部分时间都在休眠,所以无论哪个线程想要CPU时间都可以在需要运行的几纳秒内获得它。它可以做的是,如果你在核心也忙于其他正常线程的机器上运行它会导致整个事情变得不必要地变慢。在这种情况下,thead1最初不会获得任何CPU时间(因为它总是需要CPU的更高优先级的线程),然后在3秒之后,调度程序将意识到它已经饿死了永恒CPU速度(90亿CPU周期左右)的条款,并给它一个最高优先级的爆发足够长的时间让它与重要的Windows服务的时间紧密相关!幸运的是它然后睡觉,然后在完成之前做了一点工作,所以它没有任何伤害,但如果它做了任何真实的事情,它可能会对整个系统的性能产生一些非常讨厌的影响。

答案 1 :(得分:1)

您不能保证Windows何时执行特定线程。您可以向操作系统提出建议(I.E.优先级),但最终Windows将决定何时,何地和何地。

如果你想确保1在2之前开始,它在3之前开始,你应该让线程1开始线程2而线程2开始线程3。

答案 2 :(得分:0)

线程被认为是轻量级进程,因为它们完全相互独立地运行。如果您的任务在很大程度上依赖于线程执行的顺序,那么您可能不应该使用线程。

否则,您需要查看.NET框架提供的thread synchronization构造。

答案 3 :(得分:0)

您无法像这样同步线程。如果您需要按特定顺序完成工作,请不要使用单独的线程,或使用ResetEvents或类似的东西。

答案 4 :(得分:0)

永远不会保证线程调度。除非您通过锁/等明确强制执行代码,否则永远不会保留订单。