c# – ManualResetEvent vs. Thread.Sleep

我实现了以下后台处理线程,其中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);
            }
        }
    }
}
事件是由OS / Kernel提供的内核原语,仅为这种事情而设计.内核提供了一个边界,您可以在其上保证对同步至关重要的原子操作(某些原子性可以在用户空间中进行,也可以通过硬件支持).

简而言之,当一个线程等待事件时,它被放在该事件的等待列表中,并被标记为不可运行.
当事件发出信号时,内核将唤醒等待列表中的内容,并将其标记为可运行,并可继续运行.当事件发出信号时,一个线程可以立即醒来,而且长时间睡觉,然后重新检查条件,这当然是一个巨大的好处.

即使一毫秒是真的很长一段时间,你可以在那个时间处理数千个事件.此外,时间分辨率传统上是10ms,所以睡眠不到10ms通常只是导致10ms的睡眠.一个事件,一个线程可以被唤醒和安排立即

相关文章
相关标签/搜索