异步任务的 SemaphoreSlim 问题
SemaphoreSlim problems with asyc 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();
}
}
}
}
这又是从一个如下所示的列表中开始任务,这是一个自定义模型,其中包含之前存储和创建的任务
public Task Operation { get; set; }
var t = new Task(async () =>
{
await Task.Run(() => Method(input, sps));
});
记住我的代码没有像我预期的那样工作,这是开始这样的事情的正确方法吗?我不认为从一个点启动 3 个任务是个好主意。像这样的主要原因是因为我正在执行一个 Action<> 并且找不到单独等待它的方法。这些任务是否计入 SemaphoreSlim 限制?
经过各种测试,我可以确认我的 SemaphoreSlim 代码只是在连续执行任务,我在任务列表中添加了一个大的任务延迟,看看我是否可以阻止它执行,但新任务仍然有效...我错过了什么?
我的目标是限制并发任务的数量 运行,如果不清楚的话。感谢您的帮助!
编辑:我想我已经意识到我只是在等待任务的开始,而不是完成。
I think I've realised I'm only awaiting the starting of the task, not the completion.
的确,这就是问题的核心。
You shouldn't use the Task
constructor, ever, at all, for anything。就当它不存在吧。它总会把你引向一条尴尬的道路。
如果您有要稍后执行的操作,您应该使用委托:Action
or Func<T>
for synchronous work, and Func<Task>
or Func<Task<T>>
for asynchronous work。例如,如果 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);
}
}
如果 Operation
是 Action
(同步)或 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());
}
我一直在尝试使用 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();
}
}
}
}
这又是从一个如下所示的列表中开始任务,这是一个自定义模型,其中包含之前存储和创建的任务
public Task Operation { get; set; }
var t = new Task(async () =>
{
await Task.Run(() => Method(input, sps));
});
记住我的代码没有像我预期的那样工作,这是开始这样的事情的正确方法吗?我不认为从一个点启动 3 个任务是个好主意。像这样的主要原因是因为我正在执行一个 Action<> 并且找不到单独等待它的方法。这些任务是否计入 SemaphoreSlim 限制?
经过各种测试,我可以确认我的 SemaphoreSlim 代码只是在连续执行任务,我在任务列表中添加了一个大的任务延迟,看看我是否可以阻止它执行,但新任务仍然有效...我错过了什么?
我的目标是限制并发任务的数量 运行,如果不清楚的话。感谢您的帮助!
编辑:我想我已经意识到我只是在等待任务的开始,而不是完成。
I think I've realised I'm only awaiting the starting of the task, not the completion.
的确,这就是问题的核心。
You shouldn't use the Task
constructor, ever, at all, for anything。就当它不存在吧。它总会把你引向一条尴尬的道路。
如果您有要稍后执行的操作,您应该使用委托:Action
or Func<T>
for synchronous work, and Func<Task>
or Func<Task<T>>
for asynchronous work。例如,如果 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);
}
}
如果 Operation
是 Action
(同步)或 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());
}