运行大量任务

时间:2018-06-21 10:34:46

标签: c# task stack-overflow

我想创建大量任务n,并在每个任务i中使用从任务i-1获得的结果。

我想到了:

class TaskTest
{
static int count;
public static void Main()
{
    int n = 1000000;
    var t = Add(n);
    var sum = t.GetAwaiter().GetResult();
    Console.WriteLine("sum is: " + sum);
}

public static Task<int> Add(int step)
{
    Task t = new Task(() => Add(step));
    t.Start();
    if (step == 0)
        return Task.FromResult(0);
    return Task.FromResult(Add(step - 1).Result + 1);

}

static void AddWithLock(int step)
{
    if (step == 0)
        return;
    Interlocked.Increment(ref count);
    var t = Task.Factory.StartNew(state => AddWithLock(step - 1), CancellationToken.None);
    t.Wait();

}
  }

使用方法Add()可以将n的较小值(例如1000)工作,但是对于n = 1 000 000则会出现StackOwerFlowException。

Usin AddWithLock()并不是我想要的(它不使用其他任务的结果),并且它在处理大量数字时速度非常慢。

那么我该如何修改适用于n = 1百万等数字的代码?

编辑:

我尝试使用TaskCompletionSource,但仍然收到StackOverflowException。

 public static Task<int> Add2(int step)
{
    var tcs = new TaskCompletionSource<int>();

    if (step == 0)
        tcs.SetResult(0);

    else
    {
        var r = Add2(step - 1).Result;
        tcs.SetResult(r + 1);
    }
    return tcs.Task;
}

1 个答案:

答案 0 :(得分:-1)

不使用递归就足够了。它可以在我的PC(旧i7)上大约1000毫秒内完成。没有堆栈爆炸。

using System;
using System.Diagnostics;
using System.Threading.Tasks;

namespace ManyTasks
{
class Program
{
    public static void Main()
    {
        int n = 1000000;
        Task<int>[] tasks = new Task<int>[n];

        var sw = new Stopwatch();
        sw.Start();
        Task.Factory.StartNew(() =>
        {
            for (int i = 0; i < n; i++)
            {
                int j = i;
                tasks[i] = new Task<int>(() =>
                {
                    if (j == 0)

                        return 1;

                    var result = tasks[j - 1].Result + 1;
                    return result;
                });
                tasks[i].Start();
                tasks[i].Wait();
            }
        }).Wait();

        sw.Stop();
        Console.WriteLine(tasks[n - 1].Result);
        Console.WriteLine($"time: {sw.Elapsed.TotalMilliseconds:0.000}ms");


    }
}
}