我很难理解这种情况下的实际行为。在预期但之后SemaphoreSlim被处置时不执行任务实际上发生了什么?它抛出以下异常 -
System.ObjectDisposedException {"The semaphore has been disposed."}
我有一个类库 -
public class ParallelProcessor
{
private Action[] actions;
private int maxConcurrency;
public ParallelProcessor(Action[] actionList, int maxConcurrency)
{
this.actions = actionList;
this.maxConcurrency = maxConcurrency;
}
public void RunAllActions()
{
if (Utility.IsNullOrEmpty<Action>(actions))
throw new Exception("No Action Found!");
using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(maxConcurrency))
{
foreach (Action action in actions)
{
Task.Factory.StartNew(() =>
{
concurrencySemaphore.Wait();
try
{
action();
}
finally
{
concurrencySemaphore.Release();
}
});
}
}
}
}
我正在使用它 -
class Program
{
static void Main(string[] args)
{
int maxConcurrency = 3;
Action[] actions = new Action[] { () => Console.WriteLine(1), () => Console.WriteLine(2), () => Console.WriteLine(3) }; //Array.Empty<Action>();
ParallelProcessor processor = new ParallelProcessor(actions, maxConcurrency);
processor.RunAllActions();
Console.ReadLine();
}
}
有人可以对此有所了解吗?提前谢谢。
答案 0 :(得分:11)
问题在于您的using
声明。这就是事情的发生方式:
选项:
using
语句(这样您就不会丢弃信号量,但除非您使用此非常,否则这不会出现问题)using
语句内),直到完成所有任务,例如使用Parallel.ForEach
代替直接调用Task.Factory.StartNew
答案 1 :(得分:3)
您的信号量位于using
块的末尾,但由在其中创建的仍在运行的任务使用。
我建议将信号量提升到班级:
public class ParallelProcessor
{
private Action[] actions;
private SemaphoreSlim concurrencySemaphore;
public ParallelProcessor(Action[] actionList, int maxConcurrency)
{
this.actions = actionList;
concurrencySemaphore = new SemaphoreSlim(maxConcurrency);
}
public void RunAllActions()
{
if (Utility.IsNullOrEmpty<Action>(actions))
throw new Exception("No Action Found!");
foreach (Action action in actions)
{
Task.Factory.StartNew(() =>
{
concurrencySemaphore.Wait();
try
{
action();
}
finally
{
concurrencySemaphore.Release();
}
});
}
}
}
或替代方法,RunAllActions
将阻止所有操作完成:
public class ParallelProcessor
{
private Action[] actions;
private int maxConcurrency;
public ParallelProcessor(Action[] actionList, int maxConcurrency)
{
this.actions = actionList;
this.maxConcurrency = maxConcurrency;
}
public void RunAllActions()
{
if (Utility.IsNullOrEmpty<Action>(actions))
throw new Exception("No Action Found!");
using (var concurrencySemaphore = new SemaphoreSlim(maxConcurrency))
{
Task.WaitAll(actions.Select(a => Task.Run(() =>
{
concurrencySemaphore.Wait();
try { a(); }
finally { concurrencySemaphore.Release(); }
})).ToArray());
}
}
}
答案 2 :(得分:0)
我认为问题是处理已在using语句中的concurrencySemaphore。
使用的主要用途是,它会自动添加try和finally,最后它会处理使用下的对象。
https://www.codeproject.com/Articles/6564/Understanding-the-using-statement-in-C
您的案例的解决方案是删除使用或删除finally语句