[英]How can I achieve non-infinite receive and send timeouts on a socket under Compact Framework?
[英]StackOverflowException in non-infinite, recursive string search
背景。 我的脚本遇到StackOverflowException,同时递归搜索大字符串中的特定文本。 循环不是无限的; 问题发生在9,000-10,000次合法搜索之间(对于特定搜索) - 我需要它继续前进。 我正在使用尾递归(我认为),这可能是我的问题的一部分,因为我认为C#不能很好地做到这一点。 但是,我不确定如何避免在我的情况下使用尾递归。
问题(S)。 为什么发生StackOverflowException? 我的整体方法是否有意义? 如果设计很糟糕,我宁愿从那里开始,而不仅仅是避免异常。 但如果设计可以接受,我该怎么办StackOverflowException呢?
码。 我编写的课程在大量文本(大约6MB)中搜索联系人(大约500+来自指定列表)。 我正在使用的策略是搜索姓氏,然后在姓氏之前或之后的某个地方查找名字。 我需要找到给定文本中每个联系人的每个实例。 StringSearcher类有一个递归方法,它继续搜索联系人,每当找到一个联系人时返回结果,但跟踪搜索中断的位置。
我以下列方式使用此类:
StringSearcher searcher = new StringSearcher(
File.ReadAllText(FilePath),
"lastname",
"firstname",
30
);
string searchResult = null;
while ((searchResult = searcher.NextInstance()) != null)
{
// do something with each searchResult
}
总的来说,脚本似乎有效。 大多数联系人返回我期望的结果。 但是,当主搜索字符串非常常见(数千次点击),并且次要搜索字符串从未或很少发生时,似乎会出现问题。 我知道它不会卡住,因为CurrentIndex正在正常推进。
这是我正在谈论的递归方法。
public string NextInstance()
{
// Advance this.CurrentIndex to the next location of the primary search string
this.SearchForNext();
// Look a little before and after the primary search string
this.CurrentContext = this.GetContextAtCurrentIndex();
// Primary search string found?
if (this.AnotherInstanceFound)
{
// If there is a valid secondary search string, is that found near the
// primary search string? If not, look for the next instance of the primary
// search string
if (!string.IsNullOrEmpty(this.SecondarySearchString) &&
!this.IsSecondaryFoundInContext())
{
return this.NextInstance();
}
//
else
{
return this.CurrentContext;
}
}
// No more instances of the primary search string
else
{
return null;
}
}
StackOverflowException发生在this.CurrentIndex = ...
中,方法如下:
private void SearchForNext()
{
// If we've already searched once,
// increment the current index before searching further.
if (0 != this.CurrentIndex)
{
this.CurrentIndex++;
this.NumberOfSearches++;
}
this.CurrentIndex = this.Source.IndexOf(
this.PrimarySearchString,
ValidIndex(this.CurrentIndex),
StringComparison.OrdinalIgnoreCase
);
this.AnotherInstanceFound = !(this.CurrentIndex >= 0) ? false : true;
}
如果需要,我可以包含更多代码。 如果其中一种方法或变量值得怀疑,请告诉我。
*性能并不是真正的问题,因为这可能会在晚上作为计划任务运行。
你有一个1MB的堆栈。 当该堆栈空间用完并且您仍需要更多堆栈空间时,将抛出StackOverflowException
。 这可能是也可能不是无限递归的结果,运行时不知道。 无限递归只是使用更多堆栈空间的一种有效方式,然后可用(通过使用无限量)。 你可以使用一个有限的数量,这恰好比现有的更多,你会得到相同的例外。
虽然还有其他方法可以占用大量的堆栈空间,但递归是最有效的方法之一。 每种方法都根据该方法的签名和本地添加更多空间。 深度递归可以使用大量的堆栈空间,因此如果您希望深度超过几百个级别(甚至那么多),您可能不应该使用递归。 请注意,任何使用递归的代码都可以迭代编写,或使用显式Stack
。
很难说,因为没有显示完整的实现,但基于我可以看到你或多或少编写迭代器,但你没有使用C#构造(即IEnumerable
)。
我的猜测是“迭代器块”将允许您使这个算法更容易编写,更容易编写非递归,并且更有效地从调用者方。
以下是如何将此方法构造为迭代器块的高级视图:
public static IEnumerable<string> SearchString(string text
, string firstString, string secondString, int unknown)
{
int lastIndexFound = text.IndexOf(firstString);
while (lastIndexFound >= 0)
{
if (secondStringNearFirst(text, firstString, secondString, lastIndexFound))
{
yield return lastIndexFound.ToString();
}
}
}
private static bool secondStringNearFirst(string text
, string firstString, string secondString, int lastIndexFound)
{
throw new NotImplementedException();
}
这似乎不是递归是正确的解决方案。 通常,对于递归问题,您会将某些状态传递给递归步骤。 在这种情况下,你真的有一个简单的while
循环。 下面我将你的方法体放在一个循环中,并改变递归步骤continue
。 看看是否有效......
public string NextInstance()
{
while (true)
{
// Advance this.CurrentIndex to the next location of the primary search string
this.SearchForNext();
// Look a little before and after the primary search string
this.CurrentContext = this.GetContextAtCurrentIndex();
// Primary search string found?
if (this.AnotherInstanceFound)
{
// If there is a valid secondary search string, is that found near the
// primary search string? If not, look for the next instance of the primary
// search string
if (!string.IsNullOrEmpty(this.SecondarySearchString) &&
!this.IsSecondaryFoundInContext())
{
continue; // Start searching again...
}
//
else
{
return this.CurrentContext;
}
}
// No more instances of the primary search string
else
{
return null;
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.