我有一个相当大的类,其中包含大量字段(10+),一个巨大的数组(100kb)和一些非托管资源。让我举例说明
class ResourceIntensiveClass
{
private object unmaganedResource; //let it be the expensive resource
private byte[] buffer = new byte[1024 * 100]; //let it be the huge managed memory
private Action<ResourceIntensiveClass> OnComplete;
private void DoWork(object state)
{
//do long running task
OnComplete(this); //notify callee that task completed so it can reuse same object for another task
}
public void Start(object dataRequiredForCurrentTask)
{
ThreadPool.QueueUserWorkItem(DoWork); //initiate long running work
}
}
问题是start方法在第10000次迭代后永远不会返回,导致堆栈溢出。我可以在另一个线程中执行OnComplete委托,让Start方法返回,但是如果你知道的话,它需要使用额外的cpu时间和资源。那对我来说最好的选择是什么?
答案 0 :(得分:3)
是否有充分理由以递归方式进行计算?这似乎是一个简单的循环可以解决问题,从而避免了对非常深的堆栈的需求。这种设计似乎特别成问题,因为你依靠main()来设置你的递归。
答案 1 :(得分:1)
递归方法可能会非常快速地失控。您是否考虑过使用Parallel Linq? 你可以做点什么
(你的数组).AsParallel()。ForAll(item =&gt; item.CallMethod());
您还可以查看任务并行库(TPL)
通过任务,您可以定义操作并继续执行任务。
另一方面,Reactive Framework(RX)可以以异步方式处理完整事件。
答案 2 :(得分:1)
您在哪里更改taskData
的值,以使其长度等于currentTaskIndex
?由于您分配给数据的任务永远不会改变,因此它们将永远执行......
答案 3 :(得分:0)
我猜这个问题来自于使用预增量运算符:
if(c.CurrentCount < 10000)
c.Start(++c.CurrentCount);
我不确定C#中预增量的语义,也许传递给方法调用的值不是你所期望的。
但是,由于您的Start(int)
方法无论如何都要将输入的值分配给this.CurrentCount
,因此您应该安全地将其替换为:
if(c.CurrentCount < 10000)
c.Start(c.CurrentCount + 1);
分配c.CurrentCount
两次没有意义。
答案 4 :(得分:0)
如果使用线程池,我假设您正在保护计数器(c.CurrentCount),否则并发增量将导致更多活动,而不仅仅是10000次执行。
答案 5 :(得分:0)
有一个称为ManualResetEvent的简洁工具可以简化你的生活。
在您的班级中放置ManualResetEvent
并添加公开OnComplete
活动。
当您声明课程时,您可以将OnComplete
事件连接到代码中的某个位置,或者不将其连接起来并忽略它。
这有助于您的自定义类具有更正确的表单。
当你的漫长过程完成时(我猜这是在一个帖子中),只需调用ManualResetEvent
的{{3}}方法。
至于运行你的long方法,它应该在一个使用ManualResetEvent
的线程中,方式类似于下面的方法:
private void DoWork(object state)
{
ManualResetEvent mre = new ManualResetEvent(false);
Thread thread1 = new Thread(
() => {
//do long running task
mre.Set();
);
thread1.IsBackground = true;
thread1.Name = "Screen Capture";
thread1.Start();
mre.WaitOne();
OnComplete(this); //notify callee that task completed so it can reuse same object for another task
}