C# 递归调用方法(用于对象重用)

C# 递归调用方法(用于对象重用),c#,C#,我有一个相当大的类,它包含大量字段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

我有一个相当大的类,它包含大量字段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时间和资源。那么对我来说,什么是最好的选择呢?

递归方法可以很快摆脱控制。您是否考虑过使用并行Linq? 你可以这样做

您的Array.aspallel.ForAllitem=>item.CallMethod

您还可以查看任务并行库TPL

对于任务,您可以定义操作和继续任务


另一方面,反应式框架RX可以以异步方式在完成事件时处理这些问题。

递归进行计算有什么好的理由吗?这看起来像是一个简单的循环就可以做到这一点,从而避免了对非常深的堆栈的需要。这种设计似乎特别有问题,因为您依赖main来设置递归。

我猜问题是因为在这里使用了pre-increment操作符:

 if(c.CurrentCount < 10000)
    c.Start(++c.CurrentCount);

两次分配给c.CurrentCount没有意义。

如果使用线程池,我假设您正在保护计数器c.CurrentCount,否则并发增量将导致更多的活动,而不仅仅是10000次执行。

您在哪里更改taskData的值,使其长度永远等于currentTaskIndex?由于您分配给数据的任务永远不会改变,它们将永远被执行…

有一种称为a的简洁工具,可以简化您的生活

在类中放置ManualResetEvent并添加公共OnComplete事件

声明类时,可以将OnComplete事件关联到代码中的某个点,也可以不关联并忽略它

这将帮助您的自定义类具有更正确的形式

当您的长过程完成时,我猜这是在一个线程中,只需调用ManualResetEvent的方法

至于运行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
}


@matt b Start调用OnCompleteMethod,该方法调用Start。@TakeMeAsGuest-这段代码就是闻起来不对。我不知道递归是如何帮助您提高性能的?我还想知道您为什么这样实现它。在实际情况下,start方法启动另一个方法,比如在threadpool上,oncomplete是从该方法调用的,而不是直接从start调用的。是的,start在threadpool上启动其他方法,实际上,oncomplete是在另一个线程上调用的。所提供的代码只是我目前正在做的事情的一个例子,而不是真实情况。那么,您可能需要给出更多的细节,因为上面的代码可能不应该按现在的方式编写。更多的细节会有帮助。谢谢,但这门课是按原样写的。它使用非托管的昂贵资源和托管的大内存来完成长时间运行的任务。这里的问题不是我的代码,情况这里的问题不是我的代码,情况-德莱夫和其他人在这里说的是,根据你的例子,也许你编写的解决方案与情况不匹配。我认为情况非常清楚。我将委托设置为在完成时收到通知,以便继续执行下一个任务。假设任务进展是线性的。我知道第三方物流,但我想完全控制正在进行的事情,因为过程并不是那么简单。我认为rx处理在另一个线程中无法完成,我也可以这样做。无论如何,感谢使用RX,您可以在最初启动的同一线程上执行oncomplete。使用SubscribeOn方法。那么同样的情况将出现在rx上。正如我前面提到的,该代码完全是虚拟的,用于说明这种情况。在实际场景中,start在另一个线程上启动其他方法。在这些方法完成之后,这个类就可以自由地等待其他任务,直到全部完成。我不确定你要回答的是我问题的哪一部分?我的建议是使用foo+1而不是++foo。或者你是说真正的代码不支持start++foo?如果是这样,您可能希望重新处理代码示例,使其更接近真实情况。恐怕这没有帮助,因为此新示例没有显示递归-OnComplete的侦听器是否再次调用DoWork?ThreadPool.QueueUserWorkItemDoWork在将工作项排入队列后是否会返回?这甚至不是真正的递归,如果是的话,它会立即返回。但如果说订阅者方法说OnCompleteHandler方法,则会再次调用Start。我是否复制整个项目?使用线程,理解程序流的递归性质,使用委托等,但只为2个对象进行设计。嗯,答案很有启发性。这取决于你想做什么。。。Ob
以前的选择是从数组中删除任务,并确保任务完成时“currentTaskIndex”==0。然后可以返回方法并跳出递归。或者,您可以使用一个更简单的“for”循环来完成它;1-在实际代码中没有currentTaskIndex.2-那么我可以返回到哪里?向空中飞去?DoWork正在线程池中执行。它只是返回到线程池。请查看关于C中线程的这一页。。。抱歉,如果它对您来说太基本了,我更熟悉Java。谢谢,但我和线程中止、挂起、中断无关。顺便说一句,它们应该作为最后手段使用,在几乎所有情况下,它们都应该使用,并且可以使用其他技术避免。它需要创建每个任务的线程+切换到内核模式+不必要地阻塞。更清楚地说,长时间运行的任务使用io完成端口,每个任务不需要线程。
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
}