递归调用方法(用于对象重用)
本文关键字:对象 用于 调用 方法 递归 | 更新日期: 2023-09-27 17:49:44
我有一个相当大的类,其中包含大量字段(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时间和资源。那么对我来说什么是最好的选择呢?
是否有一个很好的理由来做你的计算递归?这看起来像是一个简单的循环就能达到目的,从而避免了对难以置信的深度堆栈的需要。当您依赖main()来设置递归时,这种设计似乎特别有问题。
递归方法很快就会失控。你有没有考虑过使用Parallel Linq?你可以这样写
(数组).AsParallel()。ForAll(item => item. callmethod ());
你也可以查看任务并行库(TPL)
对于任务,您可以定义一个操作和一个继续任务。
另一方面,响应式框架(RX)可以以异步方式处理这些完整的事件。
你在哪里改变taskData
的值,使其长度可以等于currentTaskIndex
?由于您分配给数据的任务永远不会改变,因此它们将永远被执行…
我猜问题是由这里使用预增量运算符引起的:
if(c.CurrentCount < 10000)
c.Start(++c.CurrentCount);
我不确定c#中预增量的语义,也许传递给方法调用的值不是你期望的。
但是由于您的Start(int)
方法将输入值分配给this.CurrentCount
作为第一步,因此您应该安全地将其替换为:
if(c.CurrentCount < 10000)
c.Start(c.CurrentCount + 1);
c.CurrentCount
赋值两次。如果使用线程池,我假设您正在保护计数器(c.CurrentCount),否则并发增量将导致更多活动,而不仅仅是10000次执行。
有一个叫做ManualResetEvent的工具可以简化你的生活。
在你的类中放置一个ManualResetEvent
,并添加一个公共OnComplete
事件。
当你声明你的类时,你可以将OnComplete
事件连接到代码中的某个位置,或者不连接它并忽略它。
这将有助于您的自定义类有更正确的形式。
当您的长进程完成时(我猜这是在线程中),只需调用ManualResetEvent
的Set方法。
至于运行你的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
}