Control total number of tasks when using Async/Await in a recursive function

六月ゝ 毕业季﹏ 提交于 2019-12-08 11:31:29

You can use a SemaphoreSlim to control the number of concurrent tasks. You initialize the semaphore to the maximum number of tasks you want to have and then each time you execute a task you acquire the semaphore and then release it when you are finished with the task.

This is a somewhat simplified version of your code that runs forever using random numbers and executes a maximum of 2 tasks at the same time.

class Program
{
    private static SemaphoreSlim semaphore = new SemaphoreSlim(2, 2);

    public static async Task CreateSPFolder(int folder)
    {
        try
        {
            await semaphore.WaitAsync();
            Console.WriteLine("Executing " + folder);
            Console.WriteLine("WaitAsync - CurrentCount " + semaphore.CurrentCount);

            await Task.Delay(2000);
        }
        finally
        {
            Console.WriteLine("Finished Executing " + folder);
            semaphore.Release();
            Console.WriteLine("Release - CurrentCount " + semaphore.CurrentCount);
        }

        var rand = new Random();
        var next = rand.Next(10);
        var children = Enumerable.Range(1, next).ToList();

        Task.WaitAll(children.Select(CreateSPFolder).ToArray());            
    }

    static void Main(string[] args)
    {
        CreateSPFolder(1).Wait();

        Console.ReadKey();
    }
}

First of all, I think your problem is not the amount of tasks but the amount of blocked threads waiting at Task.WaitAll(taskList.ToArray());. It's better to wait asynchronously in such cases (i.e. await Task.WhenAll(taskList);

Secondly, you can use TPL Dataflow's ActionBlock with a MaxDegreeOfParallelism set to 50 and just post to it for every folder to be created. That way you have a flat queue of work to be executed and when it's empty, you're done.

Pseudo code:

var block = new ActionBlock<FolderInfo>(
    async folderInfo => {
        await CreateFolderAsync(folderInfo);
        foreach (var subFolder in GetSubFolders(folderInfo))
        {
            block.Post(subFolder);
        }
    },
    new DataFlowExecutionOptions {MaxDegreeOfParallelism = 5});

block.Post(rootFolderInfo);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!