SwitchToThread / Thread.Yield vs. Thread.Sleep(0)vs. Thead.Sleep(1) [英] SwitchToThread/Thread.Yield vs. Thread.Sleep(0) vs. Thead.Sleep(1)

查看:160
本文介绍了SwitchToThread / Thread.Yield vs. Thread.Sleep(0)vs. Thead.Sleep(1)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图写最终的Yield方法来产生当前时间片到其他线程。到目前为止,我发现有几种不同的方式使线程产生其分配的时间片。我只是想确保我正确地解释他们,因为文档不是很清楚。所以,从我在stackoverflow,MSDN和各种博客文章,阅读以下选项存在,都有不同的优点/缺点:



SwitchToThread [win32] / Thread.Yield [.NET 4 Beta 1]:yield优点:大约是
Thread.Sleep(0)的两倍快$ <$ p

  • 缺点:只对同一处理器上的线程
    产生



  • Thread.Sleep(0)给任何处理器相同或更高优先级的任何线程




    • 优点:速度比
      Thread.Sleep(1)

    • 缺点:只生成相同或更高优先级的线程



    Thread.Sleep(1) :给任何处理器上的任何线程




      <缺点:最慢的选项
      Thread.Sleep(1)
      <如果
      timeBeginPeriod / timeEndPeriod
      ,通常
      暂停线程大约15ms [win32] are not used)


    Thread.SpinWait 可以用于产生线程的时间片吗?如果没有,它是用于什么?



    我有其他一些我错过了或不正确的解释。



    这是我的Yield方法到目前为止的样子:

      public static class Thread 
    {
    [DllImport(kernel32.dll)]
    static extern bool SwitchToThread

    [DllImport(winmm.dll)]
    internal static extern uint timeBeginPeriod(uint period);

    [DllImport(winmm.dll)]
    内部静态extern uint timeEndPeriod(uint period);

    ///< summary>产生当前线程到指定目标线程的时间片< / summary>
    public static void YieldTo(ThreadYieldTarget threadYieldTarget)
    {
    switch(threadYieldTarget){
    case ThreadYieldTarget.None:
    break;
    case ThreadYieldTarget.AnyThreadOnAnyProcessor:
    timeBeginPeriod(1); //将sleep减少到实际1ms而不是系统时间片大约15ms
    System.Threading.Thread.Sleep(1);
    timeEndPeriod(1); // undo
    break;
    case ThreadYieldTarget.SameOrHigherPriorityThreadOnAnyProcessor:
    System.Threading.Thread.Sleep(0);
    break;
    case ThreadYieldTarget.AnyThreadOnSameProcessor:
    SwitchToThread();
    break;
    default:throw new ArgumentOutOfRangeException(threadYieldTarget);
    }
    }
    }

    public enum ThreadYieldTarget
    {
    ///< summary>操作系统将决定何时中断线程< / summary>
    无,
    ///< summary>产生到任何处理器上的任何其他线程的时间片< / summary>
    AnyThreadOnAnyProcessor,
    ///< summary>产生到任何处理器上的相同或更高级别的其他线程的时间片
    SameOrHigherPriorityThreadOnAnyProcessor,
    ///< summary>产生到同一处理器上的任何其他线程的时间片< / summary>
    AnyThreadOnSameProcessor
    }


    解决方案

    SpinWait在超线程处理器上很有用。使用超线程,多个OS调度线程可以在同一物理处理器上运行,共享处理器资源。 SpinWait向处理器指示您没有进行任何有用的工作,并且它应该从不同的逻辑CPU运行代码。顾名思义,它通常在你旋转时使用。



    假设你有如下代码:

      while(!foo){} // Spin直到foo设置。 

    如果此线程正在超线程处理器上的线程上运行,则会消耗处理器资源,用于处理器上运行的其他线程。



    通过更改为:

      while(!foo){Thread.SpinWait(1);} 

    CPU向其他线程提供一些资源。



    SpinWait不会影响线程的操作系统调度。



    你的主要问题关于终极收益,它很大程度上取决于你的情况 - 你将无法得到一个好的答案,而不澄清你为什么你想要一个线程。从我的角度来看,产生处理器的最好方法是让线程进入等待状态,只有在有工作要做时才醒来。任何其他只是浪费CPU时间。


    I am trying to write the ultimate "Yield" method to yield the current time slice to other threads. So far I have found that there are several different ways to make the thread yield its allocated time slice. I just want to make sure I am interpreting them correctly since the documentation is not very clear. So, from what I have read on stackoverflow, MSDN and various blog posts, the following options exist that all have different advantages / disadvantages:

    SwitchToThread [win32] / Thread.Yield [.NET 4 Beta 1]: yields to any thread on same processor

    • Advantage: about twice as fast as Thread.Sleep(0)
    • Disadvantage: yields only to threads on same processor

    Thread.Sleep(0): yields to any thread of same or higher priority on any processor

    • Advantage: faster than Thread.Sleep(1)
    • Disadvantage: yields only to threads of same or higher priority

    Thread.Sleep(1): yields to any thread on any processor

    • Advantage: yields to any thread on any processor
    • Disadvantage: slowest option (Thread.Sleep(1) will usually suspend the thread by about 15ms if timeBeginPeriod/timeEndPeriod [win32] are not used)

    What about Thread.SpinWait? Can that be used for yielding the time slice of the thread? If not, what is it used for?

    I there something else I have missed or incorrectly interpreted. I'd be grateful if you could correct / add to my understanding.

    This is how my Yield method looks like so far:

    public static class Thread
    {
        [DllImport("kernel32.dll")]
        static extern bool SwitchToThread();
    
        [DllImport("winmm.dll")]
        internal static extern uint timeBeginPeriod(uint period);
    
        [DllImport("winmm.dll")]
        internal static extern uint timeEndPeriod(uint period);
    
        /// <summary>  yields time slice of current thread to specified target threads </summary>
        public static void YieldTo(ThreadYieldTarget threadYieldTarget)
        {
            switch (threadYieldTarget) {
                case ThreadYieldTarget.None: 
                    break; 
                case ThreadYieldTarget.AnyThreadOnAnyProcessor:
                    timeBeginPeriod(1); //reduce sleep to actually 1ms instead of system time slice with is around 15ms
                    System.Threading.Thread.Sleep(1); 
                    timeEndPeriod(1); //undo
                    break;
                case ThreadYieldTarget.SameOrHigherPriorityThreadOnAnyProcessor:
                    System.Threading.Thread.Sleep(0); 
                    break;
                case ThreadYieldTarget.AnyThreadOnSameProcessor:
                    SwitchToThread();
                    break;
                default: throw new ArgumentOutOfRangeException("threadYieldTarget");
            }
        }
    }
    
    public enum ThreadYieldTarget
    {
        /// <summary>  Operation system will decide when to interrupt the thread </summary>
        None,
        /// <summary>  Yield time slice to any other thread on any processor </summary>
        AnyThreadOnAnyProcessor,
        /// <summary>  Yield time slice to other thread of same or higher piority on any processor </summary>
        SameOrHigherPriorityThreadOnAnyProcessor,
        /// <summary> Yield time slice to any other thread on same processor </summary>
        AnyThreadOnSameProcessor
    }
    

    解决方案

    SpinWait is useful on hyperthreaded processors. With hyperthreading, multiple OS scheduled threads can be running on the same physical processor, sharing the processor resources. SpinWait indicates to the processor that you are not doing any useful work and that it should run code from a different logical CPU. As the name suggests, it is typically used when you are spinning.

    Suppose you have code like:

    while (!foo) {} // Spin until foo is set.
    

    If this thread is running on a thread on a hyperthreaded processor, it is consuming processor resources that could be used for other threads running on the processor.

    By changing to:

    while (!foo) {Thread.SpinWait(1);} 
    

    We are indicating to the CPU to give some resources to the other thread.

    SpinWait does not affect OS scheduling of threads.

    For your main questions about the "Ultimate Yield", it depends heavily on your situation - you won't be able to get a good answer without clarifying why you want a thread to yield. From my perspective, the best way to yield the processor is getting the thread to enter a wait state and only waking when there is work to do. Anything else is just wasting CPU time.

    这篇关于SwitchToThread / Thread.Yield vs. Thread.Sleep(0)vs. Thead.Sleep(1)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆