[C#.NET][Thread] 善用 SpinWait 处理 线程空转 以利提升性能

当我们在处理一个线程时,若需要同步等待时,以往可能会常用 Thread.Sleep,但 Thread.Sleep 会消耗 CPU 的时间配置,所以我们可以使用 Thread.SpinWait 方法 、SpinWait 结构

在 .NET4.0 以前,可以使用 Thread.SpinWait 方法

下图出自http://msdn.microsoft.com/zh-tw/library/system.threading.thread.spinwait.aspx

在 .NET4.0 以后,可以使用 SpinWait 结构

下图出自http://msdn.microsoft.com/zh-tw/library/ee722114.aspx

下图出自http://msdn.microsoft.com/zh-tw/library/system.threading.spinwait.aspx

看来,MSDN 则是建议使用 SpinWait 结构

来看个例子:

以往我常用 Stopwatch 来搭配 Thread.Sleep 来达到空转等待的目的

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 = 1 观察工作管理员结果,CPU 大约用掉了 2% (这在不同的机器会有不同的结果)。



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



现在则把 Thread.Sleep拿掉,改用 SpinWait.SpinUntil 来运行空转等待。 第一个参数是离开空转的条件,第二个参数是离开空转的时间,只要任一参数满足,则离开空转。
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%,很明显的这样的写法的确是胜于上一个方法。

结论:

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项目,建立以下控件

用户端,调用方式,这里是使用 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();
    }
}

若有谬误,烦请告知,新手发帖请多包涵

2010~2017 C# 第四季

原文:大专栏  [C#.NET][Thread] 善用 SpinWait 处理 线程空转 以利提升性能

原文地址:https://www.cnblogs.com/chinatrump/p/11496809.html

时间: 2024-10-15 10:11:11

[C#.NET][Thread] 善用 SpinWait 处理 线程空转 以利提升性能的相关文章

Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享

Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享 By D.S.Qiu 尊重他人的劳动,支持原创,转载请注明出处:http.dsqiu.iteye.com           熟悉Unity的developer都知道在Unity中的线程不能使用Unity的对象,但可以使用Unity的值类型变量,如Vector3等.这样就使得线程在Unity中显的很鸡肋和蹩脚,因为很多函数很都是UnityEngine类或函数的调用的,对于哪些是可以在多线程使用,风雨冲

[Java Performance] 线程及同步的性能 - 线程池/ThreadPoolExecutors/ForkJoinPool

线程池和ThreadPoolExecutors 虽然在程序中可以直接使用Thread类型来进行线程操作,但是更多的情况是使用线程池,尤其是在Java EE应用服务器中,一般会使用若干个线程池来处理来自客户端的请求.Java中对于线程池的支持,来自ThreadPoolExecutor.一些应用服务器也确实是使用的ThreadPoolExecutor来实现线程池. 对于线程池的性能调优,最重要的参数就是线程池的大小. 对于任何线程池而言,它们的工作方式几乎都是相同的: 任务被投放到一个队列中(队列的

Java并发编程:线程及同步的性能——线程池

线程池和ThreadPoolExecutors 虽然在程序中可以直接使用Thread类型来进行线程操作,但是更多的情况是使用线程池,尤其是在Java EE应用服务器中,一般会使用若干个线程池来处理来自客户端的请求.Java中对于线程池的支持,来自ThreadPoolExecutor.一些应用服务器也确实是使用的ThreadPoolExecutor来实现线程池. 对于线程池的性能调优,最重要的参数就是线程池的大小. 对于任何线程池而言,它们的工作方式几乎都是相同的: 任务被投放到一个队列中(队列的

2018-08-25多线程Thread类+Runnable接口+线程的6种状态

多线程: 进程:进程指正在运行的程序:确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能(进入内存运行的程序成为进程)! 线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程!一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序(线程是执行单元,一个进程可以包括多个线程,一个程序可以有多个进程)! 单线程程序:若有多个任务只能依次执行(这个任务执行完毕,下一个任务开始执行)!如:去网吧上网,网吧只能让一

通过top命令和thread dump查看JAVA线程死循环的案例

这篇文章是由一个面试的问题引出的.面试官问曰:"尔可知如何定位JAVA程序的死循环?".思虑良久,未有良策,回来查阅了下资料,经过一番曲折感觉自己解决问题的能力又提高了不少.以下是个例子,不一定很合适但足以说明一些问题. 1.查看进程ID: [[email protected] ~]$ jps3230 jar 2.按CPU使用率展示当前JAVA程序的所有线程: 其实这个地方按CPU的使用率来判定还不太好理解,以运行时间来判定可能更能说明问题些,具体的top命令可参考另外一篇文章(万能的

Smart Thread Pool (智能线程池)

STPStartInfo stp = new STPStartInfo(); stp.DisposeOfStateObjects = true; stp.CallToPostExecute = CallToPostExecute.Never; stp.ThreadPriority = ThreadPriority.Highest; stp.UseCallerCallContext = true; stp.MaxWorkerThreads = 4; //职能线程池 var smartThreadP

Nginx 引入线程池,提升 9 倍性能

转载:http://blog.csdn.net/wuliusir/article/details/50760357 众所周知,NGINX 采用异步.事件驱动的方式处理连接.意味着无需对每个请求创建专门的进程或线程,它用一个工作进程(worker process)处理多个连接和请求.为了达到这个目的,NGINX采用非阻塞模式的 socket,并利用诸如 epoll 和 kqueue 的高效方法. 全量进程(full-weight process)数很少(通常是一个 CPU 核只有一个)而且恒定.内

【插件式框架探索系列】使用多UI线程提升性能

了解WPF线程模型的都知道,UI线程负责呈现和管理UI,而UI元素(派生自 DispatcherObject)只能由创建该元素的线程来访问,这就导致了一些耗时的UI操作将影 响到整个应用程序性能,未响应及漫长的等待有时会令人抓狂,而UI线程一度成为了不可 越逾的鸿沟.对于框架来说,一个插件的行为不应该影响到其它插件及整个平台的稳定性,后来在看了 <Running WPF Application with Multiple UI Threads>和<DispatcherObject与WPF

亲身经历:软件线程数量超过硬件线程数量造成的性能问题

实现了一个简单的任务系统(Task Scheduler),用于多线程任务执行. 由于编程上的疏忽,比实际的硬件线程多创建了一个线程用于执行任务. 任务执行的部分,在Profiling工具里面,一直是耗时的部分. 发现了这个问题之后,改正,整个执行时间几乎变为原来的一半. 具体理论解释可以看这篇文章: http://www.codeguru.com/cpp/sample_chapter/article.php/c13533/Why-Too-Many-Threads-Hurts-Performanc