从数据库并行反序列化Json
这是一个场景:在一个单独的任务中,我从一个datareader读取数据,该datareader用一个字符串(JSON)表示一个单列结果集。在该任务中,我将JSON字符串添加到包装ConcurrentQueue的BlockingCollection中。同时,在主线程中,我尝试从集合中提取/排出JSON字符串,然后返回反序列化的JSON字符串 从数据库读取和反序列化的速度大致相同,因此不会因为大的BlockingCollection而导致太多内存消耗 当从数据库读取完成时,任务将关闭,然后我将反序列化所有未反序列化的JSON字符串 问题/想法: 1) TryTake是否锁定以便无法进行添加 2) 不要这样做。只要按顺序做就可以得到回报从数据库并行反序列化Json,json,c#-4.0,deserialization,task-parallel-library,Json,C# 4.0,Deserialization,Task Parallel Library,这是一个场景:在一个单独的任务中,我从一个datareader读取数据,该datareader用一个字符串(JSON)表示一个单列结果集。在该任务中,我将JSON字符串添加到包装ConcurrentQueue的BlockingCollection中。同时,在主线程中,我尝试从集合中提取/排出JSON字符串,然后返回反序列化的JSON字符串 从数据库读取和反序列化的速度大致相同,因此不会因为大的BlockingCollection而导致太多内存消耗 当从数据库读取完成时,任务将关闭,然后我将反序列
using (var q = new BlockingCollection<string>())
{
Task task = null;
try
{
task = new Task(() =>
{
foreach (var json in sourceData)
q.Add(json);
});
task.Start();
while (!task.IsCompleted)
{
string json;
if (q.TryTake(out json))
yield return Deserialize<T>(json);
}
Task.WaitAll(task);
}
finally
{
if (task != null)
{
task.Dispose();
}
q.CompleteAdding();
}
foreach (var e in q.GetConsumingEnumerable())
yield return Deserialize<T>(e);
}
使用(var q=new BlockingCollection())
{
Task=null;
尝试
{
任务=新任务(()=>
{
foreach(sourceData中的var-json)
q、 添加(json);
});
task.Start();
而(!task.IsCompleted)
{
字符串json;
if(q.TryTake(out-json))
产生返回反序列化(json);
}
Task.WaitAll(任务);
}
最后
{
如果(任务!=null)
{
task.Dispose();
}
q、 完成添加();
}
foreach(q.getconsumineGenumerable()中的变量e)
收益-收益反序列化(e);
}
问题1
TryTake是否锁定以便无法进行添加
将有一段非常短的时间无法执行add,但是这段时间可以忽略不计。从
某些并发集合类型使用轻量级
同步机制,如SpinLock、SpinWait、信号量Lim、,
和倒计时事件,这是.NETFramework4中新增的。这些
同步类型通常在短时间内使用忙旋转
在线程进入真正的等待状态之前。等待时间是什么时候
预计会很短,旋转的计算要少得多
比等待更昂贵,这涉及到昂贵的内核转换。
对于使用旋转的集合类,这种效率意味着
多线程可以以非常高的速率添加和删除项目。对于
有关旋转与阻塞的更多信息,请参阅旋转锁和锁定
等等
ConcurrentQueue和ConcurrentStack类不使用锁
完全相反,它们依靠联锁操作来实现
线程安全
问题2:
不要这样做。只要按顺序做就可以得到回报
using (var q = new BlockingCollection<string>())
{
Task task = null;
try
{
task = new Task(() =>
{
foreach (var json in sourceData)
q.Add(json);
});
task.Start();
while (!task.IsCompleted)
{
string json;
if (q.TryTake(out json))
yield return Deserialize<T>(json);
}
Task.WaitAll(task);
}
finally
{
if (task != null)
{
task.Dispose();
}
q.CompleteAdding();
}
foreach (var e in q.GetConsumingEnumerable())
yield return Deserialize<T>(e);
}
这似乎是应该走的路。与任何优化工作一样,做最简单的事情,然后进行测量!如果有一个瓶颈在这里考虑优化,但至少你会知道你的“优化”实际上是有帮助的,因为有度量来比较反对。< /P> < P>问题1 < /P>
TryTake是否锁定以便无法进行添加
将有一段非常短的时间无法执行add,但是这段时间可以忽略不计。从
某些并发集合类型使用轻量级
同步机制,如SpinLock、SpinWait、信号量Lim、,
和倒计时事件,这是.NETFramework4中新增的。这些
同步类型通常在短时间内使用忙旋转
在线程进入真正的等待状态之前。等待时间是什么时候
预计会很短,旋转的计算要少得多
比等待更昂贵,这涉及到昂贵的内核转换。
对于使用旋转的集合类,这种效率意味着
多线程可以以非常高的速率添加和删除项目。对于
有关旋转与阻塞的更多信息,请参阅旋转锁和锁定
等等
ConcurrentQueue和ConcurrentStack类不使用锁
完全相反,它们依靠联锁操作来实现
线程安全
问题2:
不要这样做。只要按顺序做就可以得到回报
using (var q = new BlockingCollection<string>())
{
Task task = null;
try
{
task = new Task(() =>
{
foreach (var json in sourceData)
q.Add(json);
});
task.Start();
while (!task.IsCompleted)
{
string json;
if (q.TryTake(out json))
yield return Deserialize<T>(json);
}
Task.WaitAll(task);
}
finally
{
if (task != null)
{
task.Dispose();
}
q.CompleteAdding();
}
foreach (var e in q.GetConsumingEnumerable())
yield return Deserialize<T>(e);
}
这似乎是应该走的路。与任何优化工作一样,做最简单的事情,然后进行测量!如果有一个瓶颈在这里考虑优化,但至少你会知道,如果你的“优化”实际上是帮助的,因为有度量来比较反对。< /P>测量将是困难的。当然,我可以在特定的环境中针对特定类型的JSON大小进行测试并得出结论,但是场景会有很大的不同。可以是一个字符串,也可以是10000。可以是一个属性JSON结构可以是20个属性…@Daniel Profiler将使您能够查看在每个代码块中花费的时间量。如果你有一个合适的环境,复制实时使用应该不会是一个问题。是的,我知道探查器会的,很难预测可能的场景数量。对不起,我不是说听起来很苛刻,但是关于锁定“相信”或“知道”?测量将很困难。当然,我可以在特定的环境中针对特定类型的JSON大小进行测试并得出结论,但是场景会有很大的不同。可以是一个字符串,也可以是10000。可以是一个属性JSON结构可以是20个属性…@Daniel Profiler将使您能够查看在每个代码块中花费的时间量。如果你有一个合适的环境,复制实时使用应该不会是一个问题。是的,我知道探查器会,很难预测可能出现的场景数量。对不起,我不是说听起来很苛刻,而是关于锁定“相信”或“知道”?