虽然我确实理解玩这个功能的严重影响(或者至少是我的想法),但我不明白为什么它会成为那些受人尊敬的程序员不会使用的东西之一,即使是那些甚至不知道的人也是如此它是什么.
假设我正在开发一个应用程序,其中内存使用量根据用户的行为而变化很大.应用程序生命周期可分为两个主要阶段:编辑和实时处理.在编辑阶段,假设创建了数十亿甚至数万亿的对象; 其中一些是小的,一些不是,有些可能有终结器,有些可能没有,并且假设它们的寿命从几毫秒到长时间不等.接下来,用户决定切换到实时阶段.在这一点上,假设性能起着根本性的作用,程序流程中的最轻微改动可能会带来灾难性的后果.然后,通过使用对象池等将对象创建减少到最小可能,然后,GC意外地进行编辑并将其全部抛弃,并且有人死亡.
问题:在这种情况下,在进入第二阶段之前调用GC.Collect()不是明智的吗?
毕竟,这两个阶段永远不会在时间上相互重叠,GC可能收集的所有优化和统计数据在这里几乎没用......
注意:正如你们中的一些人所指出的那样,.NET可能不是这样的应用程序的最佳平台,但这超出了这个问题的范围.目的是澄清GC.Collect()调用是否可以改善应用程序的整体行为/性能.我们都同意你在这种情况下做这种事情的情况非常罕见,但话说再次,GC试图猜测并且在大多数情况下做得非常好,但它仍然是猜测.
谢谢.
我喜欢TPL中Parallel.For和Parallel.ForEach扩展方法的简单性.我想知道是否有办法利用类似的东西,甚至是稍微高级的任务.
下面是SqlDataReader的典型用法,我想知道是否可能,如果是这样,如何用TPL中的东西替换下面的while循环.因为读者不能提供固定数量的迭代,所以不能使用For扩展方法,这样就可以处理我将收集的任务.我希望有人可能已经解决了这个问题,然后找出了一些与ADO.net不同的事情.
using (SqlConnection conn = new SqlConnection("myConnString"))
using (SqlCommand comm = new SqlCommand("myQuery", conn))
{
conn.Open();
SqlDataReader reader = comm.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
// Do something with Reader
}
}
}
Run Code Online (Sandbox Code Playgroud) 我正在阅读和处理大量的Sql Server数据(数百万行中有10行,100多万行+行).在每个源行上执行的处理很重要.单线程版本没有达到预期效果.我目前的并行处理版本在一些较小的批次(300,000个源行,1M个输出行)上表现非常好,但是我遇到了一些非常大的运行的Out of Memory异常.
代码受到了这里提供的答案的启发: 有没有办法将任务并行库(TPL)与SQLDataReader一起使用?
这是一般的想法:
获取源数据(数据太大而无法读入内存,因此我们将"流式传输")
public static IEnumerable<MyObject> ReadData()
{
using (SqlConnection con = new SqlConnection(Settings.ConnectionString))
using (SqlCommand cmd = new SqlCommand(selectionSql, con))
{
con.Open();
using (SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
while (dr.Read())
{
// make some decisions here – 1 to n source rows are used
// to create an instance of MyObject
yield return new MyObject(some parameters);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
一旦我们到达并行处理点,我们希望使用SqlBulkCopy对象来写入数据.因此,我们不希望并行处理单个MyObjects,因为我们希望每个线程执行批量复制.因此,我们将从上面读取另一个返回"批量"MyObjects的IEnumerable
class MyObjectBatch
{
public List<MyObject> Items { get; set; }
public MyObjectBatch (List<MyObject> …Run Code Online (Sandbox Code Playgroud) 如果我执行下面的代码,则OutOfMemoryException在该行发生
using (Bitmap bitmap1 = new Bitmap(FrameToFilePath(interval.Start - 1)))
Run Code Online (Sandbox Code Playgroud)
或者线
using (Bitmap bitmap2 = new Bitmap(FrameToFilePath(interval.End + 1)))
Run Code Online (Sandbox Code Playgroud)
当内部for语句执行大约1000次.
但是,我不知道为什么会发生OutOfMemoryException.我想我已经写了足够的东西using来处理Bitmap对象.内存泄漏发生在哪里?
class Program
{
static void Main(string[] args)
{
// Some code to initialize List<Interval> intervals
Parallel.ForEach(intervals, interval =>
{
using (Bitmap bitmap1 = new Bitmap(FrameToFilePath(interval.Start - 1)))
using (Bitmap bitmap2 = new Bitmap(FrameToFilePath(interval.End + 1)))
{
for (int i = interval.Start; i <= interval.End; i++)
{
ColorMatrix colorMatrix = new ColorMatrix(); // …Run Code Online (Sandbox Code Playgroud) 有时,将应用程序置于不良状态以查看其响应方式会很有帮助.拔掉网线或断电等事情将向我展示我的应用程序的弹性以及我的工作地点.
为此,我试图找出强制OutOfMemoryException进入.Net 的最快方法.在简单的控制台应用程序中执行此操作将允许我将此方案注入正在运行的应用程序中.处理时显然还需要考虑其他事项OutOfMemoryExceptions(例如内存碎片以及垃圾收集器如何分配不同代)但这对于本实验的范围并不重要.
更新
为了澄清问题的目的,重要的是要注意只是抛出一个内存不足的例外是没有用的,因为我想看看当内存压力增加时程序将如何反应.从本质上讲,我希望将GC激发为积极的收集模式,并监视它对性能的影响,直到该过程因内存不足异常而消失.
我正在通过Parallel.ForEach处理各种大小的PDF(简单的2MB到几百MB的高DPI扫描)并且偶尔会遇到OutOfMemoryException - 可以理解的是由于进程是32位并且Parallel产生了线程. ForEach占用了大量未知的内存消耗工作.
限制MaxDegreeOfParallelism确实有效,尽管由于所述线程的内存占用量较小而导致有大量(10k +)批量的小型PDF需要处理时的吞吐量不足.这是一个CPU繁重的过程,在遇到偶尔的大型PDF组并获得OutOfMemoryException之前,Parallel.ForEach很容易达到100%的CPU.运行Performance Profiler会将其备份.
根据我的理解,为Parallel.ForEach设置分区器不会提高我的性能.
这导致我使用TaskScheduler传递给我的Parallel.ForEach 的自定义MemoryFailPoint检查.在它周围搜索似乎有关于创建自定义TaskScheduler对象的稀缺信息.
之间寻找在.NET专业任务调度4并行扩展附加功能,在C#中的自定义的TaskScheduler这里#2各种各样的回答,我已经建立了我自己的TaskScheduler,并有我的QueueTask方法,例如:
protected override void QueueTask(Task task)
{
lock (tasks) tasks.AddLast(task);
try
{
using (MemoryFailPoint memFailPoint = new MemoryFailPoint(600))
{
if (runningOrQueuedCount < maxDegreeOfParallelism)
{
runningOrQueuedCount++;
RunTasks();
}
}
}
catch (InsufficientMemoryException e)
{
// somehow return thread to pool?
Console.WriteLine("InsufficientMemoryException");
}
}
Run Code Online (Sandbox Code Playgroud)
虽然try/catch有点贵,但我的目标是捕获600MB的可能最大大小PDF(+一点额外内存开销)将抛出OutOfMemoryException.当我捕获InsufficientMemoryException时,这个解决方案似乎杀掉了试图完成工作的线程.有了足够大的PDF,我的代码最终成为一个单一的线程Parallel.ForEach.
在Parallel.ForEach和OutOfMemoryExceptions上的Stackoverflow上发现的其他问题似乎不适合我在线程上使用动态内存的最大吞吐量的用例,并且通常只是MaxDegreeOfParallelism作为静态解决方案使用,例如:
因此,为了获得可变工作内存大小的最大吞吐量,可以:
MemoryFailPoint支票工作,我如何将线程返回到线程池中?