在LINQ lambda表达式中生成任务数组时使用SemaphoreSlim

时间:2019-07-02 13:43:54

标签: c# multithreading linq

我正在使用LINQ lambda表达式生成任务数组并将其添加到任务列表中。我想实现一个信号量,以限制在给定时间点正在处理的任务数。

以下是代表我当前拥有的代码:

class Test {
    private List<Task> tasks;

    public void Start(){
        tasks = new List<Task>();
        AddTasks();
    }

    private void AddTasks(){
        tasks.AddRange(
            items
            .Where(x => x.InProcess == false)
            .Select( async (item) = > {
                await DoWork(item);
            })
            .ToArray()
        );
    }
}

我想实现类似以下目的:

class Test {
    private List<Task> tasks;
    private SemaphoreSlim semaphore ;

    public void Start(){
        tasks = new List<Task>();
        semaphore = new SemaphoreSlim(5);
        AddTasks();
    }

    private void AddTasks(){
        tasks.AddRange(
            items
            .Where(x => x.InProcess == false)
            .Select( async (item) = > {
                await semaphore.AwaitAsync();
                try
                {
                    await DoWork(item);
                }
                catch (System.Exception)
                {

                    throw;
                }
                finally {
                    semaphore.Release();
                }
            })
            .ToArray()
        );
    }
}

但是我认为这不能正常工作,因为信号量位于任务内部。如何在LINQ查询中使用信号灯来停止生成新任务,直到等待信号灯?

2 个答案:

答案 0 :(得分:0)

您可以尝试使用此代码。它应该可以按照您的预期工作,但是我还没有尝试过。并且不要忘了在完成操作后致电await Task.WhenAll(tasks),您需要获得结果。

private void AddTasks()
    {
        tasks.AddRange(items
                       .Where(x => x.InProcess == false)
                       .Select(AddTaskAsync)
                       .ToArray());

        //later await Task.WhenAll(tasks);
    }

    private async Task AddTaskAsync(YourClass item)
    {
        await semaphore.WaitAsync();
        try
        {
            await DoWork(item);
        }
        finally
        {
            semaphore.Release();
        }
    }

答案 1 :(得分:-1)

我的示例代码确实达到了我的预期。在Task内部使用信号灯不会引起任何问题。它阻止了任务的运行,这是目标。