有人知道ExecutionContext.Capture()
和ExecutionContext.Run(context, work, state)
是否代价高昂?
是否会降低性能,建议小心使用?
我问,因为我有一个ContextItem,我将Context工作和状态保存在以后执行。因为我希望能够对执行工作时可能抛出的异常做出反应,所以如果在工作中抛出异常,我会执行回退。而且我也有最后的工作,无论如何抛出异常都会在任何情况下执行。
由于我只能使用一次ExecutionContext,因此对于其中一个ContextItem,我必须ExecutionContext.Capture()
三次...
或者这听起来像是一种完全错误的做法?
答案 0 :(得分:1)
根据@Alois Kraus的建议,我使用以下代码进行了测试,将锁定与捕获和放大相比较。排队执行:
class Program
{
private static readonly object _lock = new object();
private static readonly int numberOfItems = 1000000;
private static readonly int _numberOfIterations = 1000000;
private static void Main(string[] args)
{
MeasureTimeWithLocking();
MeasureTimeWithCapuringContext();
Console.WriteLine();
MeasureTimeWithLocking();
MeasureTimeWithCapuringContext();
Console.WriteLine();
MeasureTimeWithLocking();
MeasureTimeWithCapuringContext();
Console.ReadKey();
}
private static void MeasureTimeWithLocking()
{
List<ContextItem> items = new List<ContextItem>();
Stopwatch stopwatch = Stopwatch.StartNew();
for (int i = 0; i < numberOfItems; i++)
{
ContextItem item = new ContextItem();
item.Work1 = DoSomeWorkWithLock;
item.Work2 = DoSomeWorkWithLock;
item.Work3 = DoSomeWorkWithLock;
}
Parallel.ForEach(items, (item) =>
{
item.Work1(null);
item.Work2(null);
item.Work3(null);
});
stopwatch.Stop();
Console.WriteLine("Time elapsed with locking: " + stopwatch.Elapsed);
}
private static void MeasureTimeWithCapuringContext()
{
List<ContextItem> items = new List<ContextItem>();
Stopwatch stopwatch = Stopwatch.StartNew();
for (int i = 0; i < numberOfItems; i++)
{
ContextItem item = new ContextItem();
item.Context1 = ExecutionContext.Capture();
item.Context2 = ExecutionContext.Capture();
item.Context3 = ExecutionContext.Capture();
item.Work1 = DoSomeWork;
item.Work2 = DoSomeWork;
item.Work3 = DoSomeWork;
}
foreach (ContextItem item in items)
{
ExecutionContext.Run(item.Context1, item.Work1, null);
ExecutionContext.Run(item.Context2, item.Work2, null);
ExecutionContext.Run(item.Context3, item.Work3, null);
}
stopwatch.Stop();
Console.WriteLine("Time elapsed with capturing context: " + stopwatch.Elapsed);
}
private static void DoSomeWork(object ignored)
{
Work();
}
private static void DoSomeWorkWithLock(object ignored)
{
lock (_lock)
{
Work();
}
}
private static void Work()
{
int count = 0;
for (int i = 0; i < _numberOfIterations; i++)
{
count ++;
}
}
private class ContextItem
{
public ExecutionContext Context1 { get; set; }
public ExecutionContext Context2 { get; set; }
public ExecutionContext Context3 { get; set; }
public ContextCallback Work1 { get; set; }
public ContextCallback Work2 { get; set; }
public ContextCallback Work3 { get; set; }
}
}
结果是:
所以,如果我这样做,捕捉&amp;执行排队的费用平均比锁定贵5倍左右。
还要回答我的问题部分:
或者这听起来像是一种完全错误的做法?
我在this article读到了
如果你必须知道他们在那里,要么你正在做一些超级先进的事情,要么就是出了问题。
如果您想了解ExecutionContext,那么建议将SO作为最佳来源。 经过它并与同事一起运行一些测试之后,我意识到我使用的是ExecutionContext,它没有意义,而且它的性能比锁定更低,所以它可能也比其他线程功能/结构的性能更差。 / p>