我在我的应用程序中使用多个线程的锁定对象。
我如何检查其他线程尝试在锁定对象上工作的次数,或者在尝试更新锁定对象时浪费了多少时间?
我的代码基于最佳答案:
Mutliple threads updating array
编辑:复制的代码:
float[] bestResult;
object sync = new Object();
lock (sync)
{
if (bestResult[0] > calculatedData[0]) {
bestResult = calculatedData;
}
}
答案 0 :(得分:6)
System.Diagnostics.Stopwatch
课程可以帮助您:
float[] bestResult;
object sync = new Object();
var sw = new System.Diagnostics.Stopwatch();
sw.Start();
lock (sync)
{
sw.Stop();
if (bestResult[0] > calculatedData[0]) {
bestResult = calculatedData;
}
}
Console.WriteLine("Time spent waiting: " + sw.Elapsed);
答案 1 :(得分:1)
问题的问题是如何确定锁定请求发生的次数,或者因锁争用而浪费的时间。
问题的答案是您使用的是分析器,例如随Visual Studio Premium Edition提供的分析器。可能存在其他.NET分析器。
在每个锁定语句中添加计数/定时代码是不切实际的,因为它会有自己的锁定问题。因此,如果没有分析器,您必须执行静态分析。这不是那么可怕。嵌套循环是一个很大的线索。
锁定争用在服务器设计中最为突出。令人高兴的是,用户会话状态对会话是私有的。如果您正在使用APM(异步编程模型 - 本质上是回调),那么只要您在处理程序结束时不调用socket.BeginRead,从会话的角度来看,对状态的操作实际上是单线程的。因此,在这些条件下,仅在设置和拆除会话时才需要锁定。在会话中,这是完全没必要的。
这就是为什么我更喜欢APM而不是更新,更时尚的方式来处理并发执行。
答案 2 :(得分:1)
开始调查锁争用的一个不错的工具是Concurrency Visualizer,如here所述。不要害怕这篇博客文章来自2010年。相同的原则仍然适用于较新版本的Visual Studio的Concurrency Visualizer的新版本。
答案 3 :(得分:0)
我不是线程专家,但为了获得其他线程尝试处理对象的次数,您可能必须实现比Lock
更原始的锁定机制版本。我用一个紧密循环的Monitor.TryEnter给了它一个下面的镜头,欢迎评论。
当然,单独实现这样的事情很容易导致更长的阻塞时间和更多的块,以便获得所需的计数,并且基于这种实现肯定与内部锁定工作方式不同的事实。无论如何我花时间所以我要发布它。
class Program
{
static object lockObj = new object();
static void Main(string[] args)
{
System.Threading.Thread t = new System.Threading.Thread(proc);
System.Threading.Thread t2 = new System.Threading.Thread(proc);
t.Start();
t2.Start();
t.Join();
t2.Join();
Console.WriteLine("Total locked up time = " + (LockWithCount.TotalWaitTicks / 10000) + "ms");
Console.WriteLine("Total blocks = " + LockWithCount.TotalBlocks);
Console.ReadLine();
}
static void proc()
{
for (int x = 0; x < 100; x++)
{
using (new LockWithCount(lockObj))
{
System.Threading.Thread.Sleep(10);
}
}
}
}
上方显示了如何使用Lock() {}
using(new LockWithCount(x)) {}
来使用LockWithCount
class LockWithCount : IDisposable
{
static System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
object lockObj;
public static long TotalWaitTicks = 0;
public static long TotalBlocks = 0;
static LockWithCount()
{
watch.Start();
}
public LockWithCount(object obj)
{
lockObj = obj;
long startTicks = watch.ElapsedTicks;
if (!System.Threading.Monitor.TryEnter(lockObj))
{
System.Threading.Interlocked.Increment(ref TotalBlocks);
System.Threading.Monitor.Enter(lockObj);
System.Threading.Interlocked.Add(ref TotalWaitTicks, watch.ElapsedTicks - startTicks);
}
}
public void Dispose()
{
System.Threading.Monitor.Exit(lockObj);
}
}