这段代码不断抛出
stackoverflow exception
,我有一种感觉,要么是因为 await
关键字导致堆栈填满,要么是线程可用性问题。但是,我不确定解决此问题的最佳方法是什么。
results
变量只是StorageFiles
的集合,如果它高于1020左右,则会抛出异常;否则通常没问题。
private async void GetMusicTest()
{
var sfolder = await StorageFolder.GetFolderFromPathAsync(dir);
var query = sfolder.CreateFileQueryWithOptions(queryOptions);
var results = await query.GetFilesAsync();
for (int i = 0; i < results.Count; i++)
{
MusicProperties mp = await results[i].Properties.GetMusicPropertiesAsync();
Debug.WriteLine(mp.Title);
}
}
此代码在控制台应用程序中运行良好,但在桌面 WinForm 应用程序中使用时会引发错误。
有趣的是,如果使用
result.Count()
,则在三次迭代后抛出错误,而 results.Count
则在迭代至少一半集合(如果不是全部)后抛出错误(似乎有所不同)。它们都返回相同的值。在不导致 stackoverflow 异常或耗尽所有可用线程的情况下循环的最佳方法是什么?
为了清楚起见,即使在 .Net Core 9 中,这个问题仍然相关。 似乎在深度递归或其他堆栈密集型场景中运行时,强烈建议保护堆栈并偶尔使用 Task.Yield() 这是一个演示此行为的简短测试程序:
#define USE_TASK_YIELD // Enable or disable this to toggle Task.Yield behavior
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("Testing deep async recursion with stack depth...");
try
{
await DeepAsyncRecursion(0);
}
catch (Exception ex)
{
Console.WriteLine($"Exception: {ex.Message}");
}
Console.WriteLine("Test completed.");
}
static async Task DeepAsyncRecursion(int depth)
{
if (depth >= 10000) // Adjust depth to push limits
{
Console.WriteLine($"Reached depth: {depth}");
return;
}
// Print stack depth
int stackDepth = GetStackDepth();
Console.WriteLine($"Recursion depth: {depth}, Stack depth: {stackDepth}");
// Safeguard with Task.Yield if defined
#if USE_TASK_YIELD
if (GetStackDepth() > 100)
await Task.Yield(); // Forces the continuation to run asynchronously
#endif
// Recursive async call
await DeepAsyncRecursion(depth + 1);
// Simulate some work
await Task.Delay(10);
}
static int GetStackDepth()
{
// Count the number of frames in the stack trace
string stackTrace = Environment.StackTrace;
int frameCount = stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.None).Length;
return frameCount;
}
}