在递归函数使用异步/等待时控制任务总数 [英] Control total number of tasks when using Async/Await in a recursive function

查看:238
本文介绍了在递归函数使用异步/等待时控制任务总数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了这个code。递归通过REST调用将在Web系统文件夹。
因此,基本上,它为根节点的文件夹,然后获取所有子节点和平行并递归调用自身。 (每个孩子)

与code中的唯一的问题是,如果一个节点有太多可能的儿童,或者层次太深的话,我开始变得​​TaskCancellation错误。

我已经尝试增加超时10分钟..但是这并没有解决问题。

所以我的问题是我怎么能开始说50的任务,然后等待事情得到释放,继续只有当在50开放式插槽

目前我觉得我的code是创建任务将没有任何限制的是流经层次。

 公共异步任务CreateSPFolder(节点的节点,HttpClient的客户端,串docLib,字符串currentPath = NULL)
{
        串节点名称= Uri.EscapeDataString(节点名称);
        VAR要求=新的{__metadata =新的{TYPE =SP.Folder},ServerRelativeUrl =节点名称};
        字符串jsonRequest = JsonConvert.SerializeObject(请求);
        的StringContent strContent =新的StringContent(jsonRequest);
        strContent.Headers.ContentType = MediaTypeHeaderValue.Parse(应用/ JSON; ODATA =冗长);
        HTT presponseMessage RESP =等待client.PostAsync(CMD,strContent);
        如果(resp.IsSuccessStatus code)
        {
            currentPath =(currentPath == NULL)?节点名称:currentPath +/+节点名称;
        }
        其他
        {
            字符串内容=等待resp.Content.ReadAsStringAsync();
            Console.WriteLine(内容);
            抛出新的异常(无法创建文件夹+内容);
        }
    }    清单<任务> Tasklist命令=新的List<任务>();
    。node.Children.ToList()的ForEach(C => taskList.Add(CreateSPFolder(三,客户机,docLib,currentPath)));
    Task.WaitAll(taskList.ToArray());
}


解决方案

您可以使用 SemaphoreSlim 来控制并发任务的数量。在初始化信号量你想有,然后每次执行你获得的信号,然后再释放,当你与任务完成了任务的最大任务数。

这是运行永远使用随机数,并在同一时间执行最多2任务的code的稍微简化版本

 类节目
{
    私有静态SemaphoreSlim信号=新SemaphoreSlim(2,2);    公共静态异步任务CreateSPFolder(INT文件夹)
    {
        尝试
        {
            等待semaphore.WaitAsync();
            Console.WriteLine(执​​行+文件夹);
            Console.WriteLine(WaitAsync - CURRENTCOUNT+ semaphore.CurrentCount);            等待Task.Delay(2000);
        }
        最后
        {
            Console.WriteLine(执​​行完毕+文件夹);
            semaphore.Release();
            Console.WriteLine(释放 - CURRENTCOUNT+ semaphore.CurrentCount);
        }        VAR兰特=新的随机();
        变种下一= rand.Next(10);
        VAR孩子= Enumerable.Range(1,下一个).ToList();        Task.WaitAll(children.Select(CreateSPFolder).ToArray());
    }    静态无效的主要(字串[] args)
    {
        CreateSPFolder(1).Wait();        Console.ReadKey();
    }
}

I have written this code. It recursively creates folders in the web system by making REST Calls. So basically, it creates a folder for the root node, then gets all the child nodes and parallely and recursively calls itself. (for each child)

the only problem with the code is that if a node has too may children OR if the hierarchy is too deep, then I start getting "TaskCancellation" errors.

I have already tried increasing the timeout to 10 minutes.. but that does not solve the problem.

So my question is how can I start say 50 tasks, then wait for something to get freed and proceed only when there is an open slot in 50.

Currently I think my code is going on creating tasks without any limit as is flows through the hierarchy.

public async Task CreateSPFolder(Node node, HttpClient client, string docLib, string currentPath = null)
{
        string nodeName = Uri.EscapeDataString(nodeName);
        var request = new { __metadata = new { type = "SP.Folder" }, ServerRelativeUrl = nodeName };
        string jsonRequest = JsonConvert.SerializeObject(request);
        StringContent strContent = new StringContent(jsonRequest);
        strContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json;odata=verbose");
        HttpResponseMessage resp = await client.PostAsync(cmd, strContent);                
        if (resp.IsSuccessStatusCode)
        {                    
            currentPath = (currentPath == null) ? nodeName : currentPath + "/" + nodeName;
        }
        else
        {
            string content = await resp.Content.ReadAsStringAsync();
            Console.WriteLine(content);
            throw new Exception("Failed to create folder " + content);
        }
    }

    List<Task> taskList = new List<Task>();
    node.Children.ToList().ForEach(c => taskList.Add(CreateSPFolder(c, client, docLib, currentPath)));
    Task.WaitAll(taskList.ToArray());
}

解决方案

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();
    }
}

这篇关于在递归函数使用异步/等待时控制任务总数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆