锁定性能克隆对象与否

时间:2013-07-19 12:52:20

标签: c# multithreading performance locking

我有DataTable,可以包含大量DataRows;可以从多个线程访问此DataTable。某些线程也可以将值更改为某些行。实际上有一些搜索函数会锁定DataTable,使用linq搜索它并返回预期值,类似于:

lock(tableContent)
{
    var t = (from row in tableContent.AsEnumerable()
            where row[fieldName] != DBNull.Value && row.Field<T>(fieldName).Equals(someValue) select row);
    if (t.Any())
    { ... }
}                     

问题是:如果我克隆(锁定原始文件)DataTable并搜索克隆对象,锁定期间是否比直接搜索原始文件更快?

我认为克隆操作会将O(n)复制到每一行,所以时间与搜索相同,但我不知道是否有一些优化(内存复制,... 。)减少克隆时间或类似的东西。

1 个答案:

答案 0 :(得分:2)

克隆是O(n),但这并不能说明全部内容。克隆可以是浅克隆(只是复制表中的引用)或深度克隆(复制对象本身)。深度克隆可能是非常昂贵的操作。搜索时间也可能不同,从仅检查单个整数字段的快速搜索到比较多个值的复杂搜索,并且非常昂贵。此外,如果您的数据在您正在搜索的字段上排序,则搜索为O(log n),这将比O(n)快得多。

如果您需要考虑某人添加,修改或删除行的可能性,那么您必须锁定或克隆。如果你正在进行单一搜索,那么克隆就没有意义,因为你必须锁定表才能克隆它。除非您的搜索费用非常昂贵,否则克隆很可能比搜索时间更长。

您说修改很少见,搜索频繁。在这种情况下,我建议您使用读写器锁,它将支持无限数量的读者或一个作家。在.NET中,您可能需要ReaderWriterLockSlim。使用它,您的代码将如下所示:

private ReaderWriterLockSlim tableLock = new ReaderWriterLockSlim();

public bool Search(string s)
{
    tableLock.EnterReadLock();
    try
    {
        // do the search here
        return result;
    }
    finally
    {
        tableLock.ExitReadLock();
    }
}

任何数量的读者都可以同时搜索表格。当然,只要他们不修改它。如果要修改表,则必须获取写锁:

public void Modify(string s)
{
    tableLock.EnterWriteLock();
    try
    {
        // do the modification here
        return;
    }
    finally
    {
        tableLock.ExitWriteLock();
    }
}

当线程尝试进入写锁定时,它必须等待所有现有读取器退出。请求写入锁之后进入的读者必须等待现有读者退出,并让作者获取然后释放锁。

在与您描述的情况类似的情况下,读取器/写入器锁对我来说非常有效:频繁读取和不频繁写入。值得研究的是,如果没有别的,因为它很容易测试。

如果搜索和更新大致相同,则读取器/写入器锁仍然可以正常工作,因为它仍然允许多个读取器。想想看,如果写入更频繁,它甚至可以正常工作,同样因为它会在可能的情况下允许多次读取。当我有一个可以搜索和更新的数据结构时,我几乎总是使用ReaderWriterLockSlim

还有其他解决方案,但它们涉及自定义数据结构,这些结构可能更难以实现和维护。我建议你试试读者/作者锁。如果之后,分析显示线程仍在等待锁定并减慢应用程序的响应时间,您可以查看替代方案。

但是,我有点担心,你所做的不仅仅是搜索。您的示例选择了一堆行,然后执行if (t.Any()) { ... }。你正在做什么{ ... }?如果这需要很长时间,那么最好使代码克隆只选择您选择的行。然后,您可以将结果集上的锁定和聚会发布到您的内容,而不会影响需要访问数据结构的其他线程。