c# - SemaphoreSlim 在发布前处置?
问题描述
在对此堆栈溢出问题的已接受答案的更新中提到
信号量可能在任务完成之前被释放,并且在调用 Release() 方法时会引发异常,因此在退出 using 块之前必须等待所有创建的任务完成
这怎么可能发生?
我将代码粘贴在这里:
int maxConcurrency=10;
var messages = new List<string>();
using(SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(maxConcurrency))
{
List<Task> tasks = new List<Task>();
foreach(var msg in messages)
{
concurrencySemaphore.Wait();
var t = Task.Factory.StartNew(() =>
{
try
{
Process(msg);
}
finally
{
concurrencySemaphore.Release();
}
});
tasks.Add(t);
}
Task.WaitAll(tasks.ToArray());
}
那么 1. 为什么需要任务列表?
并且 2. 在我的情况下,没有foreach
,而是一个套接字随机接受请求并调用Task.Factory.StartNew
. 我不能等待所有线程完成。这种信号量方法还能用吗?
解决方案
为什么需要任务清单?
能够调用Task.WaitAll
以等待所有任务在处理之前完成SemaphoreSlim
。如果您不这样做,则可能会SemaphoreSlim
在所有任务完成之前ObjectDisposedException
处理concurrencySemaphore.Release()
.
您正在创建messages.Count
任务数并SemaphoreSlim
接受maxConcurrency
(10) 初始请求数。因此,例如,如果messages.Count
等于5
,则所有五个任务都将在处理tasks
之前立即启动并或多或少地添加SemaphoreSlim
- 除非您调用Task.WaitAll
.
考虑以下示例代码,其中我已注释掉调用Task.WaitAll
并将您的调用替换Process
为调用Thread.Sleep
:
int maxConcurrency = 10;
var messages = new List<string>() { "1", "2", "3" };
using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(maxConcurrency))
{
//List<Task> tasks = new List<Task>();
foreach (var msg in messages)
{
concurrencySemaphore.Wait();
var t = Task.Factory.StartNew(() =>
{
try
{
Thread.Sleep(5000);
}
finally
{
concurrencySemaphore.Release();
}
});
//tasks.Add(t);
}
//Task.WaitAll(tasks.ToArray());
}
此代码将为每个任务抛出一个ObjectDisposedException
。
我不能等待所有线程完成。这种信号量方法还能用吗?
如果您的任务访问 的任何成员,SemaphoreSlim
则在确定所有任务都已完成之前不应将其处置。如果您不能或不想等待任务完成,您可能应该将 定义SemaphoreSlim
为类的私有字段并实现IDisposable
接口。
推荐阅读
- python - 在python中获取每个月的最后一个星期五
- gulp - 在具有单个 gulp 文件的多个项目中选择一个项目文件
- asp.net - 使用 OnDataBound asp:net gridview 合并单元格后对网格视图进行排序
- azure - 如何使用 powershell 为应用服务/Web 应用启用存储帐户备份?
- c++ - C++中的显式转换函数
- sql-server - 如何在不添加新行的情况下从 sql 追加文本文件
- gitlab - 升级到 14.12 后无法访问 gitlab web UI
- angular - 角。将一个兄弟组件的选择器传递给另一个
- regex - Visual Studio 使用正则表达式在脚本标记之间查找文本
- flutter - 在 Flutter 中使用自定义包