此后台线程队列是高效的实现吗? [英] Is this Background Thread Queue a performant implementation?
问题描述
具体地说,我想知道:
在等待状态下,ManualResetEvent是否会消耗资源?上下文切换的性能下降是否适用于处于等待状态的线程?
Will the ManualResetEvent consume resources while it is in a wait state? Does the performance degradation of context switching apply to threads that are in a wait state?
如果我可以选择使用每个工作量较小的多个BackgroundThreadQueue,或者选择一个工作量较大的BackgroundThreadQueue,并且选择使用多个...等待线程队列在不执行任何操作时会影响进程性能吗?
If I have a choice to use multiple BackgroundThreadQueues that do less work each, or one BackgroundThreadQueue that does more work, and I choose to use multiple...will the waiting thread queues affect process performance while they are not doing anything?
我应该在C#中使用更好的FIFO线程队列,还是使用不同的锁定策略?
Is there a better FIFO thread queue I should be using in C#, or a different locking strategy?
任何建议都值得赞赏.
/// <summary>
/// This class is responsible for peforming actions in a FIFO order on a
/// background thread. When it is constructed, a background thread is created
/// and a manual reset event is used to trigger actions to be performed when
/// a new action is enqueued, or when one finishes. There is a ShuttingDown
/// flag that is set by calling code when it is time to destroy the thread,
/// and a QueueIsEmpty event is fired whenever the queue finishes executing
/// the last action.
/// </summary>
public class BackgroundThreadQueue : IBackgroundThreadQueue
{
#region Fields
private readonly Queue<Action> queueOfActions = new Queue<Action>();
readonly ManualResetEvent resetEvent;
private bool shuttingDown;
private bool readyToShutdown;
private readonly object lockObject = new object();
private string queuName;
#endregion Fields
#region Events
/// <summary>
/// Occurs when the BackgroundThreadQueue is empty, and ready to shut down.
/// </summary>
public event EventHandler IsReadyToShutdown;
#endregion Events
#region Constructor
public BackgroundThreadQueue(string threadName)
{
this.resetEvent = new ManualResetEvent(false);
queuName = threadName;
StartThread();
}
#endregion Constructor
#region Public Methods
public void ClearQueue()
{
lock (lockObject)
{
queueOfActions.Clear();
}
resetEvent.Set();
}
/// <summary>
/// Enqueues an action, and calls set on the manual reset event to trigger
/// the action to be performed (if no action is currently being performed,
/// the one just enqueued will be done immediately, if an action is already
/// being performed, then the one just enqueued will have to wait its turn).
/// </summary>
public void EnqueueAction(Action actionToEnqueue)
{
if (actionToEnqueue == null)
{
throw new ArgumentNullException("actionToEnqueue");
}
bool localReadyToShutDown = false;
lock (lockObject)
{
queueOfActions.Enqueue(actionToEnqueue);
if(this.readyToShutdown)
{
localReadyToShutDown = true;
this.readyToShutdown = false;
}
}
//if this instance is ready to shut down...and we just enqueued a
//new action...we can't shut down now...
if (localReadyToShutDown)
{
StartThread();
}
resetEvent.Set();
}
#endregion Public Methods
#region Public Properties
public bool ReadyToShutdown
{
get
{
lock (lockObject)
{
return this.shuttingDown && this.readyToShutdown;
}
}
private set
{
this.readyToShutdown = value;
if (this.readyToShutdown)
{
//let interested parties know that the queue is now empty
//and ready to shutdown
IsReadyToShutdown.Raise(this);
}
}
}
/// <summary>
/// Gets or sets a value indicating whether or not the queue should shut down
/// when it is finished with the last action it has enqueued to process.
/// If the queues owner is shutting down, it needs to notify the queue,
/// and wait for a QueueIsEmpty event to be fired, at which point the reset
/// event will exit ... the owner shouldn't actually destroy the queue
/// until all actions have been performed.
/// </summary>
public bool ShuttingDown
{
get
{
lock (lockObject)
{
return this.shuttingDown;
}
}
set
{
lock (lockObject)
{
bool startThread = false;
if (value == false)
{
readyToShutdown = false;
//if we were shutting down...but, now are not
startThread = this.shuttingDown;
}
this.shuttingDown = value;
//if we were shutting down, but now are not...
//we need to restart the processing actions thread
if (startThread)
{
StartThread();
}
}
this.resetEvent.Set();
}
}
#endregion Public Properties
#region Private Methods
private void StartThread()
{
var processActionsThread = new Thread(this.ProcessActions);
processActionsThread.Name = queuName;
processActionsThread.IsBackground = true;
processActionsThread.Start();
}
/// <summary>
/// Processes the actions in a while loop, resetting a ManualResetEvent that
/// is triggered in the EnqueueAction method and ShuttingDown property.
/// </summary>
private void ProcessActions()
{
while (true)
{
Action action = null;
lock (lockObject)
{
//if there are any actions, then get the first one out of the queue
if (queueOfActions.Count > 0)
{
action = queueOfActions.Dequeue();
}
}
if (action != null)
{
action();
}
lock (lockObject)
{
//if any actions were added since the last one was processed, go
//back around the loop and do the next one
if (this.queueOfActions.Count > 0)
{
continue;
}
if (this.shuttingDown)
{
//ReadyToShutdown setter will raise IsReadyToShutdown
ReadyToShutdown = true;
//get out of the method if the user has chosen to shutdown,
//and there are no more actions to process
return;
}
this.resetEvent.Reset();
}
this.resetEvent.WaitOne();
}
}
#endregion Private Methods
}
推荐答案
等待线程的存在,除了保留用于容纳线程实际堆栈的内存以及运行时或内核保留的任何记帐信息之外,不应对性能产生持续的影响他们.因此,不,真正的等待线程除了消耗RAM外什么也不会做.
The mere existence of waiting threads should have no ongoing performance impact beyond the memory reserved to house the thread's actual stack, and whatever accounting information the runtime or kernel keeps regarding them. So no, truly waiting threads aren't going to do anything except consume RAM.
也就是说,我不确定为什么要编写此代码,因为.Net内置了线程池,并且您可能更喜欢自己使用的并发工具.
That said, I'm not sure why you'd write this code, as .Net has a threadpool built in, and concurrency tools that you should probably prefer over your own.
这篇关于此后台线程队列是高效的实现吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!