gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-30 00:19:17 25 4
gpt4 key购买 nike

对于以下场景,使用MemoryBarrier在线程安全性、结果和性能方面是否有任何差异

private SomeType field;

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

lock语句(Monitor.EnterMonitor.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;
}
}
}

最佳答案

is there any difference regarding thread-safeness?

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

result?

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

performance?

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

也就是说,更好的技术是设定一个性能目标,编写明确正确的代码,然后进行测试以查看您是否达到了您的目标。如果你这样做了,不要浪费你宝贵的时间去优化已经足够快的代码;用它来优化其他不够快的东西。

你没有问的问题:

What would you do?

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

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

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

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

关于c# - Thread.MemoryBarrier 和简单属性的锁区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22457501/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com