这两种选择中哪一种更好?
在循环外锁定?
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);
}
最佳答案
视情况而定!
哪个更好 100% 取决于您的任务在做什么。
在循环内获取锁意味着您要浪费大量时间来获取和释放锁。但是,如果您的大部分时间都花在做非锁定并行事情上,它可以释放足够多的锁以获得更多并行性。
在循环顶部获取锁会阻止并行性,但会节省锁定,这与您的操作相比可能代价高昂。
所有你能做的就是看看你的分析器,找出最适合你的情况。作为引用,如果没有争用,现代硬件上的锁需要大约 100-150 次操作才能锁定/解锁(这是粗略的经验法则,而不是硬设置值)。
考虑第三种选择,它是两者的混合体:执行所有并行操作,然后批量处理串行操作。也许每 10 个对象,捕获锁并快速完成所有的串行工作。这让您可以两全其美
关于c# - 锁定并完成所有工作,还是仅在必要时松开并抓取?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25933832/