这两种选择中哪一种更好?
锁定循环外?
lock (_workLock)
{
foreach (var resultObject in getObjectTask.Result)
{
foreach (var key in resultObject.Keys)
{
string value = resultObject.GetValue(key);
_lockedObject.DoSomething(key, value);
}
}
}
或仅在访问锁定对象时锁定?
foreach (var resultObject in getObjectTask.Result)
{
foreach (var key in resultObject.Keys)
{
string value = resultObject.GetValue(key);
lock (_workLock)
_lockedObject.DoSomething(key, value);
}
}
可能有5-10个同时操作想要同时大致这样做。这是周围的代码:
var tasks =
from provider in _objectProviders
select Task.Factory.StartNew(() => provider.Objects)
.ContinueWith(getObjectTask =>
{
// One of the operation bodies from above would go here
});
var taskList = Task.WhenAll(tasks);
taskList.Wait();
// Use results from operations here
编辑:这不是一个真正的答案,所以我不是把它作为答案发布,但是在评论部分输入后,我重构了我的代码,现在我不再需要锁了:
var tasks =
(from provider in _objectProviders
select Task.Factory.StartNew(() => provider.Objects)).ToList();
while (tasks.Count > 0)
{
int completedTask = Task.WaitAny(tasks.ToArray<Task>());
var task = tasks[completedTask];
var objects = task.Result;
foreach (var resultObject in objects)
{
foreach (var key in resultObject.Keys)
{
string value = resultObject.GetValue(key);
_unlockedObject.DoSomething(key, value);
}
}
tasks.RemoveAt(completedTask);
}
答案 0 :(得分:1)
哪一个更好是100%依赖于你的任务正在做什么。
抓住环内的锁意味着您浪费了大量时间来获取和释放锁。但是,如果你花费大部分时间来做非锁定的并行操作,它可以释放锁定以获得更多的并行性。
抓住循环顶部的锁可以防止平行,但可以节省锁定,与操作相比,这可能会很昂贵。
所有你可以看看你的探查器,找出哪一个最适合你的情况。作为参考,如果没有争用,现代硬件上的锁需要大约100-150次锁定/解锁操作(这是一个粗略的经验法则,而不是硬设定值)。
考虑第三个选项,它是两者的混合:执行所有并行操作,并批量处理串行操作。也许每10个对象,抓住锁并快速完成所有的串行工作。这可以让你充分利用这两个世界