2

我有一个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并搜索克隆的对象,锁定周期会比直接搜索原始更快吗?

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

4

1 回答 1

4

克隆是 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()) { ... }. 你在那做什么{ ... }?如果这需要很长时间,您最好只克隆您选择的行。然后,您可以随心所欲地释放结果集上的锁定和聚会,而不会影响需要访问数据结构的其他线程。

于 2013-07-19T14:26:52.667 回答