2

我必须维护信息日志,这些日志可以从多个线程同时写入,但是当我需要它们时,我只使用一个线程将其出列,这在出列集合之间需要大约 5 秒的休息时间。

以下是我为 Dequeue 它编写的代码。

if (timeNotReached)
{
   InformationLogQueue.Enqueue(informationLog);
}
else
{
    int currentLogCount = InformationLogQueue.Count;
            var informationLogs = new List<InformationLog>();
            for (int i = 0; i < currentLogCount; i++)
            {
                InformationLog informationLog1;
                InformationLogQueue.TryDequeue(out informationLog1);
                informationLogs.Add(informationLog1);
            }
    WriteToDatabase(informationLogs);
}

出队后,我将其传递给 LINQ 的 insert 方法,该方法需要 List of InformationLog 插入数据库。

这是正确的方法还是有其他有效的方法可以做到这一点?

4

2 回答 2

5

您可以ConcurrentQueue<T>通过如下扩展方法直接在 Linq 语句中使用:

static IEnumerable<T> DequeueExisting<T>(this ConcurrentQueue<T> queue)
{
    T item;
    while (queue.TryDequeue(out item))
        yield return item;
}

这将使您不必连续分配新对象List<T>ConcurrentQueue<T>对象。

于 2012-09-04T08:40:10.590 回答
2

您可能应该使用 此处所述的ConcurrentQueue<T>via a 。BlockingCollection<T>


像这样的东西,

private BlockingCollection<InformationLog> informationLogs = 
    new BlockingCollection<InformationLog>(new ConcurrentQueue<InformationLog>);

然后在你的消费者线程上你可以做

foreach(var log in this.informationLogs.GetConsumingEnumerable())
{
    // process consumer logs 1 by 1. 
}

好的,这是消费多个项目的答案。在消费线程上执行此操作,

InformationLog nextLog;
while (this.informationLogs.TryTake(out nextLog, -1))
{
    var workToDo = new List<informationLog>();
    workToDo.Add(nextLog);

    while(this.informationLogs.TryTake(out nextLog))
    {
        workToDo.Add(nextLog);
    }

    // process workToDo, then go back to the queue.
}

第一个while循环以无限等待时间从队列中获取项目,我假设一旦在队列上完成添加,即被调用,一旦队列为空CompleteAdding,此调用将立即返回。false

内部 while 循环采用 50 毫秒超时的项目,这可以根据您的需要进行调整。一旦队列为空,它将返回false,然后可以处理这批工作。

于 2012-09-04T08:17:41.777 回答