我实现了以下后台处理线程,其中Jobs
是一个 Queue<T>
:
static void WorkThread()
{
while (working)
{
var job;
lock (Jobs)
{
if (Jobs.Count > 0)
job = Jobs.Dequeue();
}
if (job == null)
{
Thread.Sleep(1);
}
else
{
// [snip]: Process job.
}
}
}
这导致作业进入队列时和实际开始执行之间出现了明显的延迟(批处理作业一次性进入,每个作业相对较小)。虽然这个延迟并不是什么大问题,但我开始思考这个问题,并进行了以下更改:
static ManualResetEvent _workerWait = new ManualResetEvent(false);
// ...
if (job == null)
{
lock (_workerWait)
{
_workerWait.Reset();
}
_workerWait.WaitOne();
}
现在,线程添加作业时会锁定_workerWait
并在完成添加作业后调用_workerWait.Set()
。这种解决方案似乎立即开始处理作业,延迟完全消失。
我的问题部分是“为什么会这样发生?”,考虑到Thread.Sleep(int)
可能会休眠比您指定的时间更长,部分是“ManualResetEvent
如何实现此级别的性能?”。
编辑:由于有人问及正在排队项目的函数,因此在此提供该函数以及当前系统的完整状态。
public void RunTriggers(string data)
{
lock (this.SyncRoot)
{
this.Triggers.Sort((a, b) => { return a.Priority - b.Priority; });
foreach (Trigger trigger in this.Triggers)
{
lock (Jobs)
{
Jobs.Enqueue(new TriggerData(this, trigger, data));
_workerWait.Set();
}
}
}
}
static private ManualResetEvent _workerWait = new ManualResetEvent(false);
static void WorkThread()
{
while (working)
{
TriggerData job = null;
lock (Jobs)
{
if (Jobs.Count > 0)
job = Jobs.Dequeue();
if (job == null)
{
_workerWait.Reset();
}
}
if (job == null)
_workerWait.WaitOne();
else
{
try
{
foreach (Match m in job.Trigger.Regex.Matches(job.Data))
job.Trigger.Value.Action(job.World, m);
}
catch (Exception ex)
{
job.World.SendLineToClient("\r\n\x1B[32m -- {0} in trigger ({1}): {2}\x1B[m",
ex.GetType().ToString(), job.Trigger.Name, ex.Message);
}
}
}
}