繁体   English   中英

异步任务的 SemaphoreSlim 问题

[英]SemaphoreSlim problems with async tasks

我一直在尝试使用 SemaphoreSlim 来限制我在任何时候运行的并发任务的数量,但它似乎没有效果,可能取决于我的实现,这就是我来这里的原因。 我的 SemaphoreSlim 代码是这样的:

首先它被称为

await Task.Run(() => mc.StartAsync());

调用此方法

public async Task StartAsync()
{
    using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(5))
    {
        foreach (var task in ThreadHandler.ThreadList)
        {
            await concurrencySemaphore.WaitAsync();
            try
            {
                await Task.Run(() => task.Operation.Start());
            }
            finally
            {
                concurrencySemaphore.Release();
            }
        }
    }
}

这反过来从一个看起来像这样的列表开始一个任务,这是一个自定义的 model,之前存储和创建了任务

public Task Operation { get; set; }
var t = new Task(async () =>
{
    await Task.Run(() => Method(input, sps));
});

记住我的代码没有像我预期的那样工作,这是开始这样的事情的正确方法吗? 我不认为从一个点启动 3 个任务是个好主意。 像这样的主要原因是因为我正在执行一个Action<>并且找不到单独等待它的方法。 这些任务是否计入SemaphoreSlim限制?

经过各种测试,我可以确认我的SemaphoreSlim代码只是在连续执行任务,我在任务列表中添加了一个大的任务延迟,看看我是否可以阻止它执行,但新任务仍在启动……这是什么我不见了?

如果不清楚的话,我的目标是限制并发运行的任务数量。 感谢您的帮助!

编辑:我想我已经意识到我只是在等待任务的开始,而不是完成。

我想我已经意识到我只是在等待任务的开始,而不是完成。

确实,这就是问题的核心。

您根本不应该为任何事情使用Task构造函数 就当它不存在吧。 它总是会把你引向一条尴尬的道路。

如果您有要在稍后执行的操作,您应该使用委托: ActionFunc<T>用于同步工作, Func<Task>Func<Task<T>>用于异步工作 例如,如果Method是同步的,那么您将拥有:

public Action Operation { get; set; }
...
Operation = () => Method(input, sps);

然后你可以使用Task.Run调用它:

public async Task ProcessAsync()
{
    using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(5))
    {
        var tasks = ThreadHandler.ThreadList.Select(async task =>
        {
            await concurrencySemaphore.WaitAsync();
            try
            {
                await Task.Run(() => task.Operation());
            }
            finally
            {
                concurrencySemaphore.Release();
            }
        }).ToList();
        await Task.WhenAll(tasks);
    }
}

如果OperationAction (同步)或Func<Task> (异步),上述代码将正常工作。

但是,如果它是Action (即同步),那么您真正在做的是并行处理,而不是异步并发,并且内置类型可以帮助实现这一点:

public void Process()
{
    // Only valid if Operation is Action, not Func<Task>!
    Parallel.ForEach(
        ThreadHandler.ThreadList,
        new ParallelOptions { MaxDegreeOfParallelism = 5 },
        task => task.Operation());
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM