Null 值不能写入 BSON 文档的根级别
A Null value cannot be written to the root level of a BSON document
当我尝试在单个 insertManyAsync 方法中插入一个地址线记录列表时说大约 9,00,000 到 mongodb 集合,我收到一条错误消息 无法将 Null 值写入BSON 文档的根级别。
已检查列表中是否有任何空条目,但找不到任何条目。当我尝试搜索时,这个错误似乎不可用。
Parallel.For(0, addresslines.Count, async index =>
{
tempAddresses.Add(new TempAddress() { AddressLine1 = addresslines["AddressLine1"], Village = addresslines["Village"] });
});
/* Foreach without parallel works.
foreach (var item in pincodestrings)
{
tempAddresses.Add(new TempAddress() { AddressLine1 = DateTime.Now.ToLongDateString() }); //, AddressLine2 = "sample2", Dist_City = "sample", Pincode = 1, State = "yy", Town_Taluk = "aa", Village = "vv" });
}*/
if (tempAddresses.Count > 0)
{
await _context.QCSubmission.InsertManyAsync(tempAddresses.AsEnumerable(), null);
}
尝试过几条记录说 100 条记录工作正常。在 MongoDB 中插入批量记录有什么问题。我需要在 MongoDB 中检查和更正吗?
更新:根据评论,已将 Parallel.Foreach 替换为 for-each,这有效,但为了处理大量数据,必须使用并行来加速。
问题似乎出在多线程访问来自 System.Collection.Generic
的非线程安全集合时,当在多个线程中同时向其添加值时,可能会将缺失值或空值引入到收集或取消链接它的块和其他未定义的行为。
您可以使用 System.Collections.Concurrent
instead, in this case probably ConcurrentBag<TempAddress>
中的线程安全集合之一。
编辑:
我做了一个简短的测试来比较并行锁定和线程安全集合与使用普通 for 循环并写入标准通用集合的性能。您可能想对您的数据进行类似的测试并查看其比较情况。我 运行 这个在 DotNet fiddle 上,它建议使用普通列表可能会更快。
然而,除了在循环中写入集合之外,您做的越多,并行性就越好。
using System;
using System.Diagnostics;
public static class Module1
{
public static void Main()
{
System.Collections.Concurrent.ConcurrentBag<int> bag = new System.Collections.Concurrent.ConcurrentBag<int>();
// Test Bag Parallel
Stopwatch t = Stopwatch.StartNew();
System.Threading.Tasks.Parallel.For(0, 500000, index =>
{
bag.Add(index);
});
t.Stop();
Console.WriteLine("Parallel Bag test completed in " + t.ElapsedTicks.ToString());
// Test Bag Incremental
bag = new System.Collections.Concurrent.ConcurrentBag<int>();
t = Stopwatch.StartNew();
for (int index = 0; index <= 500000; index += 1)
{
bag.Add(index);
}
t.Stop();
Console.WriteLine("Incremental Bag test completed in " + t.ElapsedTicks.ToString());
bag = null;
// Test List Incremental
t = Stopwatch.StartNew();
System.Collections.Generic.List<int> lst = new System.Collections.Generic.List<int>();
t = Stopwatch.StartNew();
for (int index = 0; index <= 500000; index += 1)
{
lst.Add(index);
}
t.Stop();
Console.WriteLine("Incremental list test completed in " + t.ElapsedTicks.ToString());
}
}
输出:
Parallel Bag test completed in 229264
Incremental Bag test completed in 1115224
Incremental list test completed in 42385
当我尝试在单个 insertManyAsync 方法中插入一个地址线记录列表时说大约 9,00,000 到 mongodb 集合,我收到一条错误消息 无法将 Null 值写入BSON 文档的根级别。
已检查列表中是否有任何空条目,但找不到任何条目。当我尝试搜索时,这个错误似乎不可用。
Parallel.For(0, addresslines.Count, async index =>
{
tempAddresses.Add(new TempAddress() { AddressLine1 = addresslines["AddressLine1"], Village = addresslines["Village"] });
});
/* Foreach without parallel works.
foreach (var item in pincodestrings)
{
tempAddresses.Add(new TempAddress() { AddressLine1 = DateTime.Now.ToLongDateString() }); //, AddressLine2 = "sample2", Dist_City = "sample", Pincode = 1, State = "yy", Town_Taluk = "aa", Village = "vv" });
}*/
if (tempAddresses.Count > 0)
{
await _context.QCSubmission.InsertManyAsync(tempAddresses.AsEnumerable(), null);
}
尝试过几条记录说 100 条记录工作正常。在 MongoDB 中插入批量记录有什么问题。我需要在 MongoDB 中检查和更正吗?
更新:根据评论,已将 Parallel.Foreach 替换为 for-each,这有效,但为了处理大量数据,必须使用并行来加速。
问题似乎出在多线程访问来自 System.Collection.Generic
的非线程安全集合时,当在多个线程中同时向其添加值时,可能会将缺失值或空值引入到收集或取消链接它的块和其他未定义的行为。
您可以使用 System.Collections.Concurrent
instead, in this case probably ConcurrentBag<TempAddress>
中的线程安全集合之一。
编辑:
我做了一个简短的测试来比较并行锁定和线程安全集合与使用普通 for 循环并写入标准通用集合的性能。您可能想对您的数据进行类似的测试并查看其比较情况。我 运行 这个在 DotNet fiddle 上,它建议使用普通列表可能会更快。
然而,除了在循环中写入集合之外,您做的越多,并行性就越好。
using System;
using System.Diagnostics;
public static class Module1
{
public static void Main()
{
System.Collections.Concurrent.ConcurrentBag<int> bag = new System.Collections.Concurrent.ConcurrentBag<int>();
// Test Bag Parallel
Stopwatch t = Stopwatch.StartNew();
System.Threading.Tasks.Parallel.For(0, 500000, index =>
{
bag.Add(index);
});
t.Stop();
Console.WriteLine("Parallel Bag test completed in " + t.ElapsedTicks.ToString());
// Test Bag Incremental
bag = new System.Collections.Concurrent.ConcurrentBag<int>();
t = Stopwatch.StartNew();
for (int index = 0; index <= 500000; index += 1)
{
bag.Add(index);
}
t.Stop();
Console.WriteLine("Incremental Bag test completed in " + t.ElapsedTicks.ToString());
bag = null;
// Test List Incremental
t = Stopwatch.StartNew();
System.Collections.Generic.List<int> lst = new System.Collections.Generic.List<int>();
t = Stopwatch.StartNew();
for (int index = 0; index <= 500000; index += 1)
{
lst.Add(index);
}
t.Stop();
Console.WriteLine("Incremental list test completed in " + t.ElapsedTicks.ToString());
}
}
输出:
Parallel Bag test completed in 229264
Incremental Bag test completed in 1115224
Incremental list test completed in 42385