У меня есть симуляция, которая генерирует данные, которые должны быть сохранены в базе данных.
ParallelLoopResult res = Parallel.For(0, 1000000, options, (r, state) =>
{
ComplexDataSet cds = GenerateData(r);
SaveDataToDatabase(cds);
});
Симуляция генерирует большое количество данных, поэтому было бы нецелесообразно сначала генерировать их, а затем сохранять ихв базу данных (до 1 ГБ данных), и также не имеет смысла сохранять ее в базе данных один за другим (слишком маленькие трансформации для практического применения).Я хочу вставить их в базу данных как пакетную вставку с контролируемым размером (скажем, 100 с одним коммитом).
Однако я думаю, что мои знания в области параллельных вычислений меньше теоретических.Я придумал это (что, как вы видите, очень некорректно):
DataBuffer buffer = new DataBuffer(...);
ParallelLoopResult res = Parallel.For(0, 10000000, options, (r, state) =>
{
ComplexDataSet cds = GenerateData(r);
buffer.SaveDataToBuffer(cds, i == r - 1);
});
public class DataBuffer
{
int count = 0;
int limit = 100
object _locker = new object();
ConcurrentQueue<ConcurrentBag<ComplexDataSet>> ComplexDataBagQueue{ get; set; }
public void SaveDataToBuffer(ComplexDataSet data, bool isfinalcycle)
{
lock (_locker)
{
if(count >= limit)
{
ConcurrentBag<ComplexDataSet> dequeueRef;
if(ComplexDataBagQueue.TryDequeue(out dequeueRef))
{
Commit(dequeueRef);
}
_lastItemRef = new ConcurrentBag<ComplexDataSet>{data};
ComplexDataSetsQueue.Enqueue(_lastItemRef);
count = 1;
}
else
{
// First time
if(_lastItemRef == null)
{
_lastItemRef = new ConcurrentBag<ComplexDataSet>{data};
ComplexDataSetsQueue.Enqueue(_lastItemRef);
count = 1;
}
// If buffer isn't full
else
{
_lastItemRef.Add(data);
count++;
}
}
if(isfinalcycle)
{
// Commit everything that hasn't been committed yet
ConcurrentBag<ComplexDataSet> dequeueRef;
while (ComplexDataSetsQueue.TryDequeue(out dequeueRef))
{
Commit(dequeueRef);
}
}
}
}
public void Commit(ConcurrentBag<ComplexDataSet> data)
{
// Commit data to database..should this be somehow in another thread or something ?
}
}
Как вы видите, я использую очередь для создания буфера, а затем вручную решаю, когда фиксировать.Однако у меня есть сильное чувство, что это не очень эффективное решение моей проблемы.Во-первых, я не уверен, правильно ли я блокирую.Во-вторых, я не уверен, даже если это полностью поточно-ориентированный (или вообще).
Не могли бы вы взглянуть на минуту и прокомментировать, что мне делать по-другому?Или, если есть совершенно лучший способ сделать это (используя какую-то технику Продюсер-Потребитель или что-то в этом роде)?
Спасибо и наилучшие пожелания, D.