0

我有一个对象 a Product,它存储在我的应用程序的本地缓存中。这个产品缓存是使用一些 ORM 代码从数据库加载的,我不能轻易更改。为简单起见,Product是:

Public Class Product
    Public Property ID as Integer
    Public Property Name as String
    Public Property Price as Decimal
    Public Property Rank as Integer
End Class

产品存储在本地缓存中:

   Public Class ProductList
       Public Shared Function GetCache as List(Of Product)
           Static _List as List(Of Product)
           If _List is Nothing then
               'Code to load Data and populate List from DB
           End If
           Return _List
       End Function
    End Class

这被大大简化了,但你明白了。

Rank属性是根据过去 90 天的所有销售额计算得出的未绑定字段,因此常见产品在搜索中显示得更高。我想在后台线程上生成排名 - 因为它可能很耗时,并且不时刷新它。像这样的东西:

Public Sub UpdateRank
    Dim dt as Datatable
    dt = GetDataTable("exec usp_GetProductRank") 'Returns [ID, Rank]
    For each row in dt.rows
        _prod = getCache.getbyID(row.item(0))
        If _prod isnot Nothing then
            _prod.rank = row.item(1)
        End If
    Next
End Sub

更新排名时可能会使用缓存,从而导致脏读,但我很乐意接受。我想要做的是以线程安全的方式执行此操作。也就是说,更新集合而不用担心是否添加和删除东西等。

我可以使用 aSystem.ComponentModel.BackgroundWorker来执行此更新吗?我在主 UI 中使用了大量线程来处理这样的事情,但这是 DLL 中的非 UI 类。我正在考虑将缓存拉到第Dictionary(of Integer, Product)一个?

处理这个问题的最佳方法是什么?

4

1 回答 1

1

当您使用对对象的共享写访问时,您将需要使用锁或信号量来避免冲突。这样做时,它会告诉其他线程等到对象被解锁。这不需要 cpu 资源。当对象被解锁时,下一个线程可以在先到先服务的基础上访问它(理论上)。

前:

VB.Net:

Class ThreadSafe

    Private Shared _locker As Object = New Object

    Private Shared Sub Go()
        SyncLock _locker
            If (_val2 <> 0) Then
                Console.WriteLine((_val1 / _val2))
            End If
            _val2 = 0
        End SyncLock
    End Sub
End Class

C#:

class ThreadSafe
{
  static readonly object _locker = new object();
  static int _val1, _val2;

  static void Go()
  {
    lock (_locker)
    {
      if (_val2 != 0) Console.WriteLine (_val1 / _val2);
      _val2 = 0;
    }
  }
}

示例来自一本免费的电子书,它是关于多线程的极好参考: http ://www.albahari.com/threading/part2.aspx#_Locking

于 2012-10-02T07:20:38.820 回答