[C # .NET] [Thread] SpinWait take advantage of idle processing threads to facilitate improved performance

[C # .NET] [Thread] SpinWait take advantage of idle processing threads to facilitate improved performance


When we deal with a thread synchronization wait, if necessary, in the past may be used Thread.Sleep, but Thread.Sleep configuration will consume CPU time, so we can use Thread.SpinWait method, SpinWait structure

In .NET4.0 Previously, the method can be used Thread.SpinWait

The following figure from http://msdn.microsoft.com/zh-tw/library/system.threading.thread.spinwait.aspx

image

After .NET4.0, the structure can be used SpinWait

The following figure from http://msdn.microsoft.com/zh-tw/library/ee722114.aspx

image

The following figure from http://msdn.microsoft.com/zh-tw/library/system.threading.spinwait.aspx

image

It seems, MSDN is recommended SpinWait structure

Look at an example:

Stopwatch in the past I used to go with Thread.Sleep to achieve the purpose of idle waiting

public void Start(Action action)
{
    if (this.IsRunning)
    {
        return;
    }

    this.IsRunning = true;

    Task.Factory.StartNew(() =>
    {
        Stopwatch watch = new Stopwatch();
        while (this.IsRunning)
        {
            watch.Restart();
            action.Invoke();

            while (watch.ElapsedMilliseconds < this.Interval)
            {
                Thread.Sleep(1);
            }
        }
    });
}

把 this.Interval = 1 观察工作管理员结果,CPU 大约用掉了 2% (这在不同的机器会有不同的结果)。

SNAGHTML137db49f_thumb

若是把 Thread.Sleep(1) 拿掉,CPU 负荷将近半载

SNAGHTML137f38fd_thumb


现在则把 Thread.Sleep拿掉,改用 SpinWait.SpinUntil 来运行空转等待。

image

第一个参数是离开空转的条件,第二个参数是离开空转的时间,只要任一参数满足,则离开空转。

public void Start(Action action)
{
    if (this.IsRunning)
    {
        return;
    }

    this.IsRunning = true;

    Task.Factory.StartNew(() =>
    {
        while (this.IsRunning)
        {
            action.Invoke();
            SpinWait.SpinUntil(() => !this.IsRunning, this.Interval);
        }
    });
}

我们同样用 this.Interval = 1 来观察空转的效果,结果是 0%,很明显的这样的写法的确是胜于上一个方法。

SNAGHTML1385dd20_thumb

结论:

PS.基本上 UI 更新的越快CPU飙的越高,若没有空转 UI 没办法更新。

所以我们可以把 Thread.Sleep(1) 可以换成 SpinWait.SpinUntil(() => false, 1)


完整程序,它没有防呆,请不要将 TextBox 设成 0 或空。

public class Polling
{
    private int _interval = 1000;

    public int Interval
        {
            get { return _interval; }
            set { _interval = value; }
        }
    public bool IsRunning { get; internal set; }

    public void Start(Action action)
    {
        if (this.IsRunning)
        {
            return;
        }

        this.IsRunning = true;

        Task.Factory.StartNew(() =>
        {
            while (this.IsRunning)
            {
                action.Invoke();
                SpinWait.SpinUntil(() => !this.IsRunning, this.Interval);
            }
        });
    }

    public void Stop()
    {
        if (!this.IsRunning)
        {
            return;
        }
        this.IsRunning = false;
    }
}

建立Winform项目,建立以下控件

image

用户端,调用方式,这里是使用 SynchronizationContext 更新 UI

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        m_SynchronizationContext = SynchronizationContext.Current;
    }

    private SynchronizationContext m_SynchronizationContext;

    private Polling _polling = new Polling();
    private int _counter = 0;

    private void button1_Click(object sender, EventArgs e)
    {
        this._polling.Interval = int.Parse(this.textBox1.Text);
        this._polling.Start(() =>
        {
            this._counter++;
            m_SynchronizationContext.Post(a => { this.label1.Text = this._counter.ToString(); }, null);
        });
    }

    private void button2_Click(object sender, EventArgs e)
    {
        this._polling.Stop();
    }
}

If any error, please notify the novice posting him to bear

2010 ~ 2017 C # in the fourth quarter

Original: Large column  [C # .NET] [Thread] SpinWait make good use of idle processing threads to facilitate improved performance


Guess you like

Origin www.cnblogs.com/chinatrump/p/11496809.html