锁定并完成所有工作,或仅在必要时释放和抓取?

时间:2014-09-19 12:21:48

标签: c# .net multithreading

这两种选择中哪一种更好?

锁定循环外?

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);
}

1 个答案:

答案 0 :(得分:1)

它取决于!

哪一个更好是100%依赖于你的任务正在做什么。

抓住环内的锁意味着您浪费了大量时间来获取和释放锁。但是,如果你花费大部分时间来做非锁定的并行操作,它可以释放锁定以获得更多的并行性。

抓住循环顶部的锁可以防止平行,但可以节省锁定,与操作相比,这可能会很昂贵。

所有你可以看看你的探查器,找出哪一个最适合你的情况。作为参考,如果没有争用,现代硬件上的锁需要大约100-150次锁定/解锁操作(这是一个粗略的经验法则,而不是硬设定值)。

考虑第三个选项,它是两者的混合:执行所有并行操作,并批量处理串行操作。也许每10个对象,抓住锁并快速完成所有的串行工作。这可以让你充分利用这两个世界