我必须维护信息日志,这些日志可以同时从多个线程写入,但是当我需要它们时,我只使用一个线程将它出列,它会在出列集合之前中断大约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方法,该方法需要将InformationLog List插入数据库。
这是正确的方式还是有其他有效的方法来做到这一点?
答案 0 :(得分:1)
您应该按BlockingCollection<T>
所述的here使用ConcurrentQueue<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
,然后可以处理这批工作。
答案 1 :(得分:0)
您可以通过以下扩展方法直接在Linq语句中使用ConcurrentQueue<T>
:
static IEnumerable<T> DequeueExisting<T>(this ConcurrentQueue<T> queue)
{
T item;
while (queue.TryDequeue(out item))
yield return item;
}
这样可以避免不必分配新的List<T>
和ConcurrentQueue<T>
对象。