首页 > 解决方案 > 异步运行多个任务并在任务完成时将新任务添加到任务列表中

问题描述

抱歉标题不好,我不知道如何简洁地描述这一点。

我正在.net core 中构建一个服务来处理文件。一般的想法是(在循环中)通过使用 DB 调用检查要在文件上运行的新任务,如果找到,则将它们异步触发。会有一个限制器来限制正在运行的任务的数量。如果它达到限制,它会等到一个任务完成后再启动一个新的。如果 DB 调用没有返回任何内容,那么它只会休眠一会儿,然后再试一次。

我认为相当基本,但我遇到了问题,因为我读过的所有内容都说您应该始终等待任务,而不是“开火就忘记”。但如果我这样做,那么我要么同步运行文件,要么批量处理它们。我错过了一些我确定的东西。

目前它被实现为 IHostedService(特别是BackgroundService)。这是我们完成工作的主要 ExecuteAsync 方法。实施为“一劳永逸”。(Visual Studio 在 Task.Run 上给出“呼叫未等待”警告)

  protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {

        var throttleTimeout = 10000;
        //set up semaphore
        var taskThrottler = new SemaphoreSlim(10, 10);          

        while (!stoppingToken.IsCancellationRequested)
        {

            //wait for free slot
            await taskThrottler.WaitAsync(throttleTimeout,stoppingToken);

            //get next file to process
            var currentFile = await _fileService.GetNextFileForProcessing();

            // create task
            Task.Run( async
                () =>
                {
                    try
                    {
                        //do work with file tracker
                        var result  = await _fileProcessorController.ProcessFile(currentFile);

                    }
                    finally
                    {
                        taskThrottler.Release();
                    }
                }                    
                , stoppingToken);


        }
    }

现在,如果我更改它并在 Task.Run 之前添加等待,那么我(本质上)将同步运行,因为每个任务将在下一个任务被触发之前被等待..

如果我将任务添加到列表中,我可以使用“await Task.WhenAll(tasks);”。但后来我在批处理。

我需要能够优雅地处理失败的处理作业,所以我认为必须以某种形式等待。

我发现的所有解决类似问题的示例通常都有提前完成的任务(或文件)列表,然后迭代。但是当我需要在处理其他任务时将任务添加到列表中时,我不确定最好的方法是什么。

也许使用任务列表和WhenAny的东西?然后如果找到任何新任务,我可以在每个循环的任务列表中添加新任务吗?

标签: c#asp.net-core

解决方案


推荐阅读