Thread.MemoryBarrier 和简单属性的锁区别

2023-12-07

对于以下场景,有什么区别吗关于使用之间的线程安全性、结果和性能MemoryBarrier

private SomeType field;

public SomeType Property
{
    get
    {
        Thread.MemoryBarrier();
        SomeType result = field;
        Thread.MemoryBarrier();
        return result;
    }
    set
    {
        Thread.MemoryBarrier();
        field = value;
        Thread.MemoryBarrier();
    }
}

and lock陈述 (Monitor.Enter and Monitor.Exit)

private SomeType field;
private readonly object syncLock = new object();

public SomeType Property
{
    get
    {
        lock (syncLock)
        {
            return field;
        }
    }
    set
    {
        lock (syncLock)
        {
            field = value;
        }
    }
}

因为引用分配是原子的,所以我认为在这种情况下我们确实需要任何锁定机制。

表现MemeoryBarrier 比 Release 的锁实现快大约 2 倍。这是我的测试结果:

Lock
Normaly: 5397 ms
Passed as interface: 5431 ms

Double Barrier
Normaly: 2786 ms
Passed as interface: 3754 ms

volatile
Normaly: 250 ms
Passed as interface: 668 ms

Volatile Read/Write
Normaly: 253 ms
Passed as interface: 697 ms

ReaderWriterLockSlim
Normaly: 9272 ms
Passed as interface: 10040 ms

Single Barrier: freshness of Property
Normaly: 1491 ms
Passed as interface: 2510 ms

Single Barrier: other not reodering
Normaly: 1477 ms
Passed as interface: 2275 ms

以下是我在 LINQPad 中测试它的方法(在首选项中设置了优化):

void Main()
{   
    "Lock".Dump();
    string temp;
    var a = new A();
    var watch = Stopwatch.StartNew();
    for (int i = 0; i < 100000000; ++i)
    {
        temp = a.Property;
        a.Property = temp;
    }
    Console.WriteLine("Normaly: " + watch.ElapsedMilliseconds + " ms");
    Test(a);

    "Double Barrier".Dump();
    var b = new B();
    watch.Restart();
    for (int i = 0; i < 100000000; ++i)
    {
        temp = b.Property;
        b.Property = temp;
    }
    Console.WriteLine("Normaly: " + watch.ElapsedMilliseconds + " ms");
    Test(b);

    "volatile".Dump();
    var c = new C();
    watch.Restart();
    for (int i = 0; i < 100000000; ++i)
    {
        temp = c.Property;
        c.Property = temp;
    }
    Console.WriteLine("Normaly: " + watch.ElapsedMilliseconds + " ms");
    Test(c);

    "Volatile Read/Write".Dump();
    var d = new D();
    watch.Restart();
    for (int i = 0; i < 100000000; ++i)
    {
        temp = d.Property;
        d.Property = temp;
    }
    Console.WriteLine("Normaly: " + watch.ElapsedMilliseconds + " ms");
    Test(d);

    "ReaderWriterLockSlim".Dump();
    var e = new E();
    watch.Restart();
    for (int i = 0; i < 100000000; ++i)
    {
        temp = e.Property;
        e.Property = temp;
    }
    Console.WriteLine("Normaly: " + watch.ElapsedMilliseconds + " ms");
    Test(e);

    "Single Barrier: freshness of Property".Dump();
    var f = new F();
    watch.Restart();
    for (int i = 0; i < 100000000; ++i)
    {
        temp = f.Property;
        f.Property = temp;
    }
    Console.WriteLine("Normaly: " + watch.ElapsedMilliseconds + " ms");
    Test(f);

    "Single Barrier: other not reodering".Dump();
    var g = new G();
    watch.Restart();
    for (int i = 0; i < 100000000; ++i)
    {
        temp = g.Property;
        g.Property = temp;
    }
    Console.WriteLine("Normaly: " + watch.ElapsedMilliseconds + " ms");
    Test(g);
}

void Test(I a)
{
    string temp;
    var watch = Stopwatch.StartNew();
    for (int i = 0; i < 100000000; ++i)
    {
        temp = a.Property;
        a.Property = temp;
    }

    Console.WriteLine("Passed as interface: " + watch.ElapsedMilliseconds + " ms\n");
}

interface I
{
    string Property { get; set; }
}

class A : I
{
    private string field;
    private readonly object syncLock = new object();

    public string Property
    {
        get
        {
            lock (syncLock)
            {
                return field;
            }
        }
        set
        {
            lock (syncLock)
            {
                field = value;
            }
        }
    }
}

class B : I
{
    private string field;

    public string Property
    {
        get
        {
            Thread.MemoryBarrier();
            string result = field;
            Thread.MemoryBarrier();
            return result;
        }
        set
        {
            Thread.MemoryBarrier();
            field = value;
            Thread.MemoryBarrier();
        }
    }
}

class C : I
{
    private volatile string field;

    public string Property
    {
        get
        {
            return field;
        }
        set
        {
            field = value;
        }
    }
}

class D : I
{
    private string field;

    public string Property
    {
        get
        {
            return Volatile.Read(ref field);
        }
        set
        {
            Volatile.Write(ref field, value);
        }
    }
}

class E : I
{
    private string field;
    private ReaderWriterLockSlim locker = new ReaderWriterLockSlim();

    public string Property
    {
        get
        {
            locker.EnterReadLock();
            string result = field;
            locker.ExitReadLock();
            return result;
        }
        set
        {
            locker.EnterReadLock();
            field = value;
            locker.ExitReadLock();
        }
    }
}

class F : I
{
    private string field;

    public string Property
    {
        get
        {
            Thread.MemoryBarrier();
            return field;
        }
        set
        {
            field = value;
            Thread.MemoryBarrier();
        }
    }
}

class G : I
{
    private string field;

    public string Property
    {
        get
        {
            string result = field;
            Thread.MemoryBarrier();
            return result;
        }
        set
        {
            Thread.MemoryBarrier();
            field = value;
        }
    }
}

关于线程安全有什么区别吗?

两者都确保在读写周围设置适当的屏障。

result?

在这两种情况下,两个线程都可以竞相写入一个值。然而,读取和写入不能在时间上向前或向后移动超过锁或完整栅栏。

表现?

您已经以两种方式编写了代码。现在运行它。如果您想知道哪个更快,请运行它并找出答案!如果您有两匹马并且您想知道哪匹马更快,请与它们比赛。不要在网上询问陌生人他们认为哪匹马更快。

也就是说,更好的技术是设定绩效目标,将代码写得明显正确,然后测试看看是否达到了目标。如果您这样做了,请不要浪费宝贵的时间来尝试进一步优化已经足够快的代码;把它花在优化其他不够快的东西上。

一个你没有问过的问题:

你会怎么办?

我不会编写多线程程序,这就是我要做的。如果必须的话,我会使用进程作为并发单位。

如果我必须编写一个多线程程序,那么我会使用可用的最高级别的工具。我会使用任务并行库,我会使用异步等待,我会使用Lazy<T>等等。我会避免共享内存;我将线程视为异步返回值的轻量级进程。

如果我必须编写一个共享内存多线程程序那么我会始终锁定一切。如今,我们经常编写程序通过卫星链路获取十亿字节的视频并将其发送到手机。花 20 纳秒获取锁定不会杀死你。

我不够聪明,无法尝试编写低锁代码,所以我根本不会这样做。如果当时我必须这么做的话我会使用低锁代码来构建更高级别的抽象并使用该抽象。幸运的是,我不必这样做,因为有人已经构建了我需要的抽象。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Thread.MemoryBarrier 和简单属性的锁区别 的相关文章

随机推荐

  • 如何将运行lwuit的j2me转换为android?

    如何将使用 lwuit 库的 J2ME 应用程序转换为 Android apk 我尝试使用 mircoemulator 进行转换 但是当我启动应用程序时 它显示错误并退出 读这篇文章 适用于 Android 的 LWUIT 这里清楚地讲述了
  • ggplot2中仅显示一个文本值

    我试图将文本打印限制为条形图中的一个变量 我怎样才能只标记粉红色的条601 215 399 456 ggplot df aes Var1 value label value fill Var2 geom bar stat identity
  • cassandra 2.2 CQl Shell 支持 python 2.7

    尝试启动 cql Shell 时出现错误 gt cqlsh CQL Shell supports only Python 2 7 gt 我已经安装了python2 7但它仍然给出相同的错误 我必须设置一些路径吗 我已经使用此命令从 data
  • Python - 使用 pandas 多重处理多个大尺寸文件

    我有一个y csv文件 文件大小为 10 MB 包含来自Jan 2020 to May 2020 我每个月还有一个单独的文件 例如data 2020 01 csv 它包含详细的数据 每个月文件的文件大小约为1 GB 我正在分割y csv按月
  • GUI 在循环时变得无响应

    单击按钮后 表单将变得无响应 直到解析函数完成其工作 我想将 searchAll 函数移至线程 我确实阅读了类似问题的几个答案 但我不明白如何 class MyForm QDialog def init self super init se
  • 连接到 SFTP 服务器时出现 SocketException:名称有效,但未找到请求类型的数据

    我正在尝试使用 SharpSsh 库连接我的 sftp 服务器 但出现以下错误 System Net Sockets SocketException 0x80004005 The requested name is valid but no
  • Flutter 在本机应用程序中打开本地资源(PDF)

    我正在尝试将我的应用程序与 PDF 捆绑在一起 并让用户在本机查看器中打开它 我努力了 将 PDF 的数据复制到 临时目录 或 文档目录 来自 path provider 并从那里打开 要打开 我使用 url launcher 打开文件 我
  • 使用 angular2 限制输入字段的长度

    我已经实现了使用 angular2 限制输入字段的指令 它在桌面浏览器中工作正常 但在 Android 移动设备中无法工作 成分 import LimitToDirective from directives limitedvalidati
  • 按两个变量组进行汇总

    考虑一个简化的数据集 真实的数据集有更多的列和行 df tp tf weight 1 FWD RF 78 86166 2 MF LF 81 04566 3 DEF LF 80 70527 4 DEF LF 82 96071 5 DEF RF
  • 如何将position_dodge()和geom_line()与重叠分组结合起来?

    当 x 轴上的分组变量 颜色和线条重叠但总是不同时 是否可以使用 geom line 在躲避点之间绘制一条线 下图中的灰线应该始终连接两个具有相同名称的数据点 它们位于相同的分组 2 x 轴 内 但位于不同的分组 2 颜色 中 可重现的例子
  • 如何在silverstripe数据扩展中自动发布图像

    我试图将上传字段添加到自定义数据扩展并让图像字段正常工作 但是 我上传的图像仍处于概念模式 我必须转到 文件 选项卡才能发布它 我尝试使用 Silverstripe 文档中提供的代码 但这似乎只适用于常规页面 我发现了一个和我类似的问题 如
  • 在 .htaccess 中使用自定义环境变量

    我需要这样的东西 SetEnv foo bar baz RewriteEngine On RewriteCond HTTP HOST foo RewriteRule http www foo 1 L UPD 我做了如下 SetEnv HOS
  • Struts 2 文件上传 - 空指针异常

    我正在尝试结合使用 Struts2 和 Spring 来上传文件 但是 不知怎的 在到达我的动作课 我的文件之后 filename和文件内容类型都出来了null 我尝试寻找问题所在 但没有结果 下面是我的文件上传的代码 index jsp
  • 如何使用 Mockito 和 JUnit 检查方法中的 if 语句?

    我有我应该测试的方法 代码 当然有些部分被删掉了 public class FilterDataController public static final String DATE FORMAT yyyy MM dd Autowired p
  • 在docker下安装时可以回答对话框问题吗?

    是否可以以某种方式回答使用 apt get 安装某些软件包时以对话框形式出现的问题 例如 我正在尝试设置一个包含以下内容的容器mail stack delivery包装内含 FROM ubuntu RUN apt get install y
  • 如何在android中使用sax解析器从xml读取imageUrl在网格视图中显示图像

    我是安卓新手 我想创建一个应用程序来从 URL 读取 XML 文件并使用图像的 ImageUrl 在网格视图中显示图像 感谢您的回答 但我可以从 url 读取 xml 文件 但我需要 xml imageUrl 是否存在 以便在网格视图中显示
  • 计算原始输入中的元音数

    我有一个家庭作业问题 要求通过原始输入读取字符串并计算字符串中有多少个元音 这是我到目前为止所拥有的 但我遇到了一个问题 def vowels vowels a e i o u count 0 string raw input Enter
  • 运行“sudo pip”有哪些风险?

    偶尔我会遇到评论或回应该状态强调运行pip under sudo是 错误 或 坏 但在某些情况下 包括我设置一堆工具的方式 它要么更简单 要么甚至有必要以这种方式运行 跑步有哪些风险pip under sudo 请注意 这与以下问题不同th
  • 在定义整个映射之前,如何引用映射中的变量?

    我将从我的代码开始 因为它应该更容易理解我想要做什么 function get color color lightness return map get map get colors color lightness colors green
  • Thread.MemoryBarrier 和简单属性的锁区别

    对于以下场景 有什么区别吗关于使用之间的线程安全性 结果和性能MemoryBarrier private SomeType field public SomeType Property get Thread MemoryBarrier So