我有一个类的实例,该实例从多个线程访问。此类接受这些调用并将元组添加到数据库中。由于某些数据库约束条件,我需要以串行方式执行此操作,因为并行线程可能导致数据库不一致。
由于我对C#中的并行和并发是新手,因此我执行了以下操作:
private BlockingCollection<Task> _tasks = new BlockingCollection<Task>();
public void AddDData(string info)
{
Task t = new Task(() => { InsertDataIntoBase(info); });
_tasks.Add(t);
}
private void InsertWorker()
{
Task.Factory.StartNew(() =>
{
while (!_tasks.IsCompleted)
{
Task t;
if (_tasks.TryTake(out t))
{
t.Start();
t.Wait();
}
}
});
}
AddDData
被多个线程调用,InsertDataIntoBase
是一个非常简单的插入操作,应该只需几毫秒时间。问题在于,由于我的知识不足,我无法确定原因,有时会调用两次任务!它总是这样进行的:T1 T2 T3 T1 <- 主键错误。 T4
我是否完全误解了
.Take()
,或者我漏掉了什么,或者我的生产者/消费者实现真的很糟糕?最好的问候,拉斐尔。更新:如建议所示,我使用此架构制作了一个快速沙盒测试实现,并且正如我怀疑的那样,它不能保证在上一个任务完成之前不会触发下一个任务。所以问题仍然存在:如何正确排队任务并按顺序执行它们?
更新2:我简化了代码。
private BlockingCollection<Data> _tasks = new BlockingCollection<Data>();
public void AddDData(Data info)
{
_tasks.Add(info);
}
private void InsertWorker()
{
Task.Factory.StartNew(() =>
{
while (!_tasks.IsCompleted)
{
Data info;
if (_tasks.TryTake(out info))
{
InsertIntoDB(info);
}
}
});
}
请注意,我已经将任务删除,因为我依赖于同步的InsertIntoDB调用(因为它在循环内部),但仍然没有成功......生成是正确的,我绝对确定只有唯一的实例进入队列。但无论我尝试什么,有时都会使用相同的对象两次。
Task.CurrentId
)写入命令行并查看输出。当启动100万个以上的任务时,我无法复现此问题... - Austin Salonen