我有这个简单的代码...
var map = new ReferencedEntityMapAce(uow);
...效果很好
但是现在我需要在不同的线程上运行它(由于其递归,栈空间很大),并等待其结果再继续。
最简单的方法是什么? (我看不到给Task分配特定线程或告诉它创建具有大堆栈的线程的方法)
背景(如果需要): 上面我使用了几个月的代码突然开始引发堆栈溢出异常。我相信我已经达到了极限,因为它现在正在处理具有关系的近14万个实体,以决定应保存它们的顺序以初始化新数据库。 我无法更改递归部分-在我使用的外部第三方库中,没有计划对其进行更新。
我已经破解了测试代码,以证明当在大堆栈线程上进行处理时,它确实可以工作。
答案 0 :(得分:1)
您可以将Thread
类与maxStackSize
构造函数一起使用,但如果要保留Task
的语义,则必须实现自定义TaskScheduler
,如下所示:
public class BigStackTaskScheduler : TaskScheduler
{
private int _stackSize;
public BigStackTaskScheduler(int stackSize)
{
_stackSize = stackSize;
}
// we don't need to keep a tasks queue here
protected override IEnumerable<Task> GetScheduledTasks()
{
return new Task [] { };
}
protected override void QueueTask(Task task)
{
var thread = new Thread(ThreadWork, _stackSize);
thread.Start(task);
}
// we aren't going to inline the execution
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
QueueTask(task);
return false;
}
private void ThreadWork(object obj)
{
if (obj is Task task)
TryExecuteTask(task);
}
}
class Program
{
async static Task Test()
{
var taskFactory = new TaskFactory(
CancellationToken.None, TaskCreationOptions.DenyChildAttach,
TaskContinuationOptions.None, new BigStackTaskScheduler(0xffff * 2));
await taskFactory.StartNew(() => { Console.WriteLine("Task"); });
}
static void Main(string[] args)
{
Test().Wait();
}
}
更新:
自定义TaskScheduler
的替代方案可以使用TaskCompletionSource
:
class Program
{
static Task<TOut> ThreadWithCustomStack<TIn, TOut>(Func<TIn, TOut> action, TIn arg, int stackSize)
{
var tcs = new TaskCompletionSource<TOut>();
var thread = new Thread(new ThreadStart(() =>
{
try
{
tcs.SetResult(action(arg));
}
catch (Exception e)
{
tcs.SetException(e);
}
}), stackSize);
thread.Start();
thread.Join();
return tcs.Task;
}
async static Task Test()
{
var result = await ThreadWithCustomStack(
arg => { Console.WriteLine("Task"); return arg.ToString(); },
2,
0xffff * 2);
}
static void Main(string[] args)
{
Test().Wait();
}
}