Lock使用及效率分析(C#)

news2025/1/16 19:09:22

    针对无Lock、Lock、ReadWriterLock、ReadWriterLockSlim四种方式,测试在连续写的情况下,读取的效率(原子操作Interlocked由于使用针对int,double等修改的地方特别多,而且使用范围受限,所以本文章没有测试)

先说结论: 

锁类型每分钟运行次数1每分钟运行次数2每分钟运行次数3平均
无lock97998684805410369707429891871339.3
lock81270863711143288735108479912091.7
ReadWriterLock74970270893500328587993783400079.7
ReadWriterLockSlim85942306922061338880262188983686.7

运行环境:

运行效率:无lock>ReadWriteLockSlim>ReadWriterLock>lock

一、无Lock

多线程读写易造成数据错误,这里不是为了复现数据错误,而是为了测试无Lock方式的读取效率

private IntellVega.Project.Develop.Models.CustomSetting Compensation
{
    get
    {
        return _compensation;
    }
    set
    {
        _compensation = value;
    }
}

private void InitCommand()
{
    WriteCommand = new RelayCommand(Write);
    ReadCommand = new RelayCommand(Read);
}

private void Write()
{
    Task.Run(() =>
    {
        while (true)
        {
            IntellVega.Project.Develop.Models.CustomSetting compensation = new IntellVega.Project.Develop.Models.CustomSetting();
            Random random = new Random();
            compensation.FocusCompensation = random.NextDouble();
            Compensation = compensation;
        }
    });
}

private void Read()
{
    Time = 0;
    Task.Run(() =>
    {
        Stopwatch sw = Stopwatch.StartNew();
        while (true)
        {
            if (sw.ElapsedMilliseconds > 60 * 1000) { break; }
            double d = Compensation.FocusCompensation;
            Time++;
        }
    });
}

二、lock

lock是一种比较好用的简单的线程同步方式,它是通过为给定对象获取互斥锁来实现同步的。它可以保证当一个线程在关键代码段的时候,另一个线程不会进来,它只能等待,等到那个线程对象被释放,也就是说线程出了临界区。

lock的参数必须是基于引用类型的对象,不要是基本类型像bool,int什么的,这样根本不能同步,原因是lock的参数要求是对象,如果传入int,势必要发生装箱操作,这样每次lock的都将是一个新的不 同的对象。最好避免使用public类型或不受程序控制的对象实例,因为这样很可能导致死锁。特别是不要使用字符串作为lock的参数,因为字符串被CLR“暂留”,就是说整个应用程序中给定的字符串都只有一个实例,因此更容易造成死锁现象。建议使用不被“暂留”的私有或受保护成员作为参数。其实某些 类已经提供了专门用于被锁的成员,比如Array类型提供SyncRoot,许多其它集合类型也都提供了SyncRoot。

  所以,使用lock应该注意以下几点: 

  1、如果一个类的实例是public的,最好不要lock(this)。因为使用你的类的人也许不知道你用了lock,如果他new了一个实例,并且对这个实例上锁,就很容易造成死锁。

  2、如果MyType是public的,不要lock(typeof(MyType))

  3、永远也不要lock一个字符串

private IntellVega.Project.Develop.Models.CustomSetting Compensation
{
    get
    {
        lock (_obj)
        {
            return _compensation;
        }
    }
    set
    {
        lock (_obj)
        {
            _compensation = value;
        }
    }
}

三、ReadWriterLock方式

在考虑资源访问的时候,惯性上我们会对资源实施lock机制,但是在某些情 况下,我们仅仅需要读取资源的数据,而不是修改资源的数据,在这种情况下获取资源的独占权无疑会影响运行效率,因此.Net提供了一种机制,使用ReaderWriterLock进行资源访问时,如果在某一时刻资源并没有获取写的独占权,那么可以获得多个读的访问权,单个写入的独占权,如果某一时 刻已经获取了写入的独占权,那么其它读取的访问权必须进行等待

private IntellVega.Project.Develop.Models.CustomSetting Compensation
{
    get
    {
        try
        {
            _readWriterLock.AcquireReaderLock(1000);
            return _compensation;
        }
        finally
        {
            _readWriterLock.ReleaseReaderLock();
        }
    }
    set
    {
        _readWriterLock.AcquireWriterLock(1000);
        _compensation = value;
        _readWriterLock.ReleaseWriterLock();
    }
}

四、ReadWriterLockSlim方式

 ReaderWriterLockSlim 类似于 ReaderWriterLock,只是简化了递归、升级和降级锁定状态的规则。 ReaderWriterLockSlim 可避免多种潜在的死锁情况。 此外,ReaderWriterLockSlim 的性能明显优于 ReaderWriterLock。 建议在所有新的开发工作中使用 ReaderWriterLockSlim
摘自:链接:https://www.jianshu.com/p/a3e69ed17c8a
 

private IntellVega.Project.Develop.Models.CustomSetting Compensation
{
    get
    {
        try
        {
            _readWriterSlimLock.EnterReadLock();
            return _compensation;
        }
        finally
        {
            _readWriterSlimLock.ExitReadLock();
        }
    }
    set
    {
        try
        {
            _readWriterSlimLock.EnterUpgradeableReadLock();
            try
            {
                _readWriterSlimLock.EnterWriteLock();
                _compensation = value;
            }
            finally
            {
                _readWriterSlimLock.ExitWriteLock();
            }
        }
        finally
        {
            _readWriterSlimLock.ExitUpgradeableReadLock();
        }
    }
}

--END

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1091724.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【高级交换技术】配置QinQ终结子接口接入VLL示例

简介 VLL是建立在MPLS技术上的点到点二层隧道技术,可以在MPLS骨干网上透明传输二层数据,从而使得位于不同物理位置的属于同一个VLAN的站点之间可以相互通信。 QinQ终结子接口接入VLL是指在报文通过VLL网络传输前,先由设备上的路由子接口对设…

【数据分享】2022年我国30米分辨率的坡向数据(免费获取)

地形数据,也叫DEM数据,是我们在各项研究中最常使用的数据之一。之前我们分享过2022年哥白尼30米分辨率的DEM高程数据,该数据被公认为是全球最佳的开源DEM数据之一,甚至没有之一(可查看之前的文章获悉详情)&…

Map中的那些事

Map中的那些事 Map中的那些事拓展时间复杂度O(1):常数级O(logn):对数级O(n):线性级O(nlog n):线性对数级O(n):平方级O(n):立方级O(2的n次方):指数级 hashMaphashMap基本知识哈希冲突的定义hashMap的实现原理hashMap有四个构造器 具体问题HashMap的内部数据结构HashMap允许空键空…

MySQL的各种锁

1. MySQL有遇到过死锁的问题吗?你是如何解决的? 死锁,就是两个或两个以上的线程在执行过程中,去争夺同一个共享资源导致互相等待的现象,在没有外部干预的情况下,线程会一直处于阻塞状态,无法往下…

自动化办公篇之python批量改名

#批量命名 import xlwings as xw app xw.App(visibleFalse,add_bookFalse) workbook app.books.open("测试表.xlsx") for sheet in workbook.sheets:sheet.namesheet.name.replace("彩印之","银河") workbook.save() app.quit()

一篇文章带你用动态规划解决打家劫舍问题

动态规划的解题步骤可以分为以下五步,大家先好好记住 1.创建dp数组以及明确dp数组下标的含义 2.制定递推公式 3.初始化 4.遍历顺序 5.验证结果 根据打家劫舍的题意:两个直接相连的房子在同一天晚上被打劫会触发警报 所以我们制定出核心策略——偷东…

Generalizable NeRF in ICCV‘23

文章目录 前置知识Generalizable《Enhancing NeRF akin to Enhancing LLMs: Generalizable NeRF Transformer with Mixture-of-View-Experts》《WaveNeRF: Wavelet-based Generalizable Neural Radiance Fields》NeO 360: Neural Fields for Sparse View Synthesis of Outdoor …

习题2.18

有点烦了,改个次序做题发博文。今天先发2.18 题目很简单 将列表反序。用clojure来写,还是有点不习惯。忽然想起来,以前面试遇到过面试题,要求用递归函数对数组反序。原来就是想考察这些内容。 因为源语言已经有提供reverse&#…

2023最新接口自动化测试面试题

1、get和post的区别? l http是上层请求协议,主要定义了服务端和客户端的交互规格,底层都是tcp/ip协议 l Get会把参数附在url之后,用?分割,&连接不同参数,Get获取资源,post会把…

Python安装和环境配置教程

进官网根据不同的操作系统,下载适合自己的编译环境(在百度里直接输入Python) 选择安装包(我选择的是3.8.0版本) python官方下载目录中有好多种安装方式,一般情况选择Windows x86-64 executable installer …

酒水茶叶经营小程序商城的作用是什么

酒水茶叶的用户群体非常广,其价格从低到高覆盖了很多人群,对酒厂茶商或经销商来说,在市场高需求的同时,其所遇经营难题也比较明显。 通过【雨科】平台搭建酒水茶叶商城,实现商品线上自营售卖,电脑手机端小程…

缩短从需求到上线的距离:集成多种工程实践的稳定框架 | 开源日报 No.55

zeromicro/go-zero Stars: 25.7k License: MIT go-zero 是一个集成了各种工程实践的 web 和 rpc 框架。通过弹性设计保障了大并发服务端的稳定性,经受了充分的实战检验。 go-zero 包含极简的 API 定义和生成工具 goctl,可以根据定义的 api 文件一键生成…

【git】500 Whoops, something went wrong on our end.

在访问公的的git 时出现了500错误提示. 500 Whoops, something went wrong on our end. 哎呀,我们这边出了问题。 TMD 出了什么问题了???一脸懵逼。 登录git 服务器。 查看git的状态。 命令: gitlab-ctl statu…

【AI视野·今日Sound 声学论文速览 第二十四期】Thu, 12 Oct 2023

AI视野今日CS.Sound 声学论文速览 Thu, 12 Oct 2023 Totally 12 papers 👉上期速览✈更多精彩请移步主页 Daily Sound Papers Enhancing expressivity transfer in textless speech-to-speech translation Authors Jarod Duret LIA , Benjamin O Brien LIA , Yanni…

【C++】 局部对象,引用返回

1、new 关键字 会在堆内申请空间,如果仅仅是普通调用构造函数,不会在堆内开辟空间。 2、函数调用会形成栈帧,进行压栈操作,函数调用结束,会进行弹栈。 函数内的局部对象,会随着弹栈,而被销毁(…

关于github申请学生认证-卡在证明上传环节解决方案

在持有学信网英语翻译(30)某宝请人代注册(80) 通过github security log和聊天记录我大致猜想了下做法,前面的学校邮箱其实都好说主要是下面的那个上传照片的环节卡了我很久

生活空间中,餐桌该如何选择?福州中宅装饰,福州装修

餐桌设计 如何选择 不同的餐桌,定义不同的餐桌礼仪 在家的装修设计上, 很多人的关注点是这样的: 玄关收纳要强、客厅颜值要高、阳台功能要全、厨房要好用、卧室要舒适......餐厅、几把椅子一张长桌,够了吧。 餐厅说:“…

20.2 FMC驱动SDRAM的时序初始化实现及内存测试

继续上一篇的话题,写到SDRAM通过CubeMx配置后,在工程代码编写时直接引用的是我事先写好的时序初始化、内存测试文件,而未对其进行详细的解释,所以本篇文章就来娓娓道来。不多说,开始吧 SDRAM的初始化流程简述 SDRAM初…

在不同版本的linx编译erLang时出现./configure使用--prefix指定路径后,总在指定的另前多了/usr/local路径

昨天别的项目同事遇到一个编译遇到在不同linx版本下编译erLang的源码时,其中有一个版本的编译出现在./configure时加入---prefix指定编译后的安装目录,总会在指定的安装另前多了/usr/local的目录,导致无法源码安装到普通用户指定的目录 安装…

目录启示:使用 use 关键字为命名空间内的元素建立非限定名称

文章目录 参考环境三种名称非限定名称限定名称完全限定名称举个栗子 useuse 关键字use ... as .. 命名冲突真假美猴王两个世界 参考 项目描述搜索引擎Bing、GoogleAI 大模型文心一言、通义千问、讯飞星火认知大模型、ChatGPTPHP 官方PHP ManualPHP 官方language.namespaces.ra…