【问题标题】:FIFO / QUEUE with buffer and thread-safe具有缓冲区和线程安全的 FIFO / QUEUE
【发布时间】:2011-06-19 09:50:52
【问题描述】:

我收到了大量需要插入数据库的统计数据。 我想实现某种保留所有数据的 Queue 或 FIFO 类 当它达到特定计数(缓冲区)时,它将通过批量插入将该数据发送到 SQL。这应该是线程安全的。

我知道如何进行批量插入。 任何建议如何制作队列/列表?

谢谢

【问题讨论】:

  • 你在.Net 4下运行吗?

标签: c# .net asp.net vb.net


【解决方案1】:

.net 基类库有 ConcurrentQueue(Of T) 。只需导入System.Collections.Concurrent。

编辑:如果您必须使用队列,您可以创建一个包装类/模块,当计数器(缓冲区)达到一定数量时触发事件。

【讨论】:

  • 当您达到缓冲区限制并将其设为线程安全时,回调函数会怎样?
【解决方案2】:

如果您不需要严格的 FIFO,我认为您应该使用 BlockingCollection。

它是线程安全的,实现看起来像这样:

var collection = new BlockingCollection<Data>();

var sqlinserter = Task.Factory.StartNew(UpdateSql());

while (true) {
    Data statistics = FetchStatistics();
    if (statistics == null)
        break;
    collection.Add(statistics);
}
collection.CompleteAdding();
sqlinserter.Wait();

编辑 看到您想在每批中插入特定数量的项目

void UpdateSql() {
    var batch = new List<Data>();
    foreach (var item in collection.GetConsumingEnumerable()) {
        batch.Add(item);
        if (batch.Count > SomeBatchSize) {
            InsertIntoSql(batch);
            batch.Clear();
        }
    }
    if (batch.Count > 0)
        InsertIntoSql(batch); // insert remaining items
}

【讨论】:

    【解决方案3】:

    这是一种安全的处理方式。 主要是要避免任何可能“卡在”同步锁中的情况。

    Public Class TSQueue(Of T)
    
        Private q As New Queue(Of T)
        Public Property threshold As Integer = 100
        Public Event ThresholdHit As EventHandler(Of EventArgs)
    
        Public Sub EnqueueSafe(value As T)
            Dim notify As Boolean = False
            SyncLock q
                q.Enqueue(value)
                If q.Count >= threshold Then
                    notify = True
                End If
            End SyncLock
            If notify Then
                RaiseEvent ThresholdHit(Me, EventArgs.Empty)
            End If
        End Sub
    
        Public Function DequeueSafe() As T
            SyncLock q
                Return q.Dequeue()
            End SyncLock
        End Function
    
        Public Function DequeueAllSafe() As T()
            Dim out() As T
            SyncLock q
                out = q.ToArray()
                q.Clear()
            End SyncLock
            Return out
        End Function
    
        Public Function CountSafe() As Integer
            SyncLock q
                Return q.Count
            End SyncLock
        End Function
    
    End Class
    

    【讨论】:

    • 我很惊讶这不是答案,因为问题实际上是“......实现某种队列或 FIFO 类来保留所有数据以及何时达到特定计数(缓冲区) ,它将通过批量插入将该数据发送到SQL。这应该是线程安全的。任何建议如何制作队列/列表?事件 ThresholdHit 将触发数据转储,并且后台队列通过 synclock 语句是线程安全的。
    猜你喜欢
    • 2012-09-04
    • 2016-12-26
    • 1970-01-01
    • 1970-01-01
    • 2012-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-22
    相关资源
    最近更新 更多