在对this stack-overflow question的可接受答案的更新中,提到
信号量可能在任务完成之前被处理,并且在调用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
。我不能等待所有线程完成。可以继续使用这种信号量方法吗?
答案 0 :(得分:0)
为什么需要任务列表?
在处置Task.WaitAll
之前,可以调用SemaphoreSlim
等待所有任务完成。如果您不这样做,则SemaphoreSlim
可能在所有任务完成之前就被处理掉了,然后当其余任务中的任何一个调用ObjectDisposedException
时,您将得到一个concurrencySemaphore.Release()
。>
您正在创建messages.Count
个任务,而SemaphoreSlim
接受maxConcurrency
(10)个初始请求。因此,例如,如果messages.Count
等于5
,则将立即处理所有五个任务,并在tasks
被处置之前或多或少地将其添加到SemaphoreSlim
中-除非您调用{{ 1}}。
考虑以下示例代码,在该示例中,我已将对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
接口。