ManualResetEvent的对比了Thread.Sleep [英] ManualResetEvent vs. Thread.Sleep

查看:178
本文介绍了ManualResetEvent的对比了Thread.Sleep的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我采取了以下后台处理线程,其中工作队列< T>

 静态无效WorkThread()
{
    而(工作)
    {
        VAR工作;        锁定(职位)
        {
            如果(Jobs.Count大于0)
                工作= Jobs.Dequeue();
        }        如果(作业== NULL)
        {
            Thread.sleep代码(1);
        }
        其他
        {
            // [剪断]:处理作业。
        }
    }
}

该生产正在进入作业时之间的延迟noticable,当他们实际上开始运行(作业批次是在一旦进入,每一个工作只是[比较]小)的延迟是不是巨大的交易,但我一想到这个问题,并提出了以下变化:

 静态的ManualResetEvent _workerWait =新的ManualResetEvent(假);
// ...
    如果(作业== NULL)
    {
        锁定(_workerWait)
        {
            _workerWait.Reset();
        }
        _workerWait.WaitOne();
    }

当线程增加就业机会,现在锁定 _workerWait 键,通话 _workerWait.Set()时,它的完成增加就业机会。该解决方案(貌似)立即开始处理工作,并且延迟是完全消失了。

我的问题是部分为什么会发生这种情况?,理所当然地认为 Thread.sleep代码(INT)可以很好地入睡时间超过指定,部分如何请问的ManualResetEvent 达到这样的性能水平?

编辑:由于有人问有关的排队项目的功能,在这里它是,与整个系统一起,因为它代表的时刻

 公共无效RunTriggers(字符串数据)
{
    锁定(this.SyncRoot)
    {
        this.Triggers.Sort((A,B)=> {返回a.Priority - b.Priority;});        的foreach(在this.Triggers触发器触发)
        {
            锁定(职位)
            {
                Jobs.Enqueue(新的TriggerData(在此,触发器,数据));
                _workerWait.Set();
            }
        }
    }
}静态专用的ManualResetEvent _workerWait =新的ManualResetEvent(假);
静态无效WorkThread()
{
    而(工作)
    {
        的TriggerData工作= NULL;        锁定(职位)
        {
            如果(Jobs.Count大于0)
                工作= Jobs.Dequeue();            如果(作业== NULL)
            {
                _workerWait.Reset();
            }
        }        如果(作业== NULL)
            _workerWait.WaitOne();
        其他
        {
            尝试
            {
                的foreach(在job.Trigger.Regex.Matches匹配M(job.Data))
                    job.Trigger.Value.Action(job.World,M);
            }
            赶上(异常前)
            {
                job.World.SendLineToClient(\\ r \\ n \\ X1B [32米 - {0}触发器({1}):{2} \\ X1B [M
                    。ex.GetType()的ToString(),job.Trigger.Name,ex.Message);
            }
        }
    }
}


解决方案

该事件是由OS /内核的设计只是为这种事情提供的内核元。内核提供了一个边界时,你可以保证原子操作是同步重要的(有些原子可以在用户空间与硬件支持来完成太)。

总之,当一个线程在等待它把该事件等候名单上,并标记为非可运行的事件。
当信号的情况下,内核唤醒在等待名单中的人与它们标记为可运行的,他们可以继续运行。这是自然的,一个线程可以唤醒时立即事件发出信号,VS沉睡了很久,每一个现在,然后重新检查条件的巨大的好处。

即使一毫秒是一个真正的很长一段时间,你可以在那个时候已经处理成千上万的事件。另外,时间分辨率为10ms的传统,所以睡眠小于10ms通常只是导致10ms的睡眠反正。随着一个事件,一个线程可以被唤醒,并立即安排

I implemented the following background processing thread, where Jobs is a 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.
        }
    }
}

This produced a noticable delay between when the jobs were being entered and when they were actually starting to be run (batches of jobs are entered at once, and each job is only [relatively] small.) The delay wasn't a huge deal, but I got to thinking about the problem, and made the following change:

static ManualResetEvent _workerWait = new ManualResetEvent(false);
// ...
    if (job == null)
    {
        lock (_workerWait)
        {
            _workerWait.Reset();
        }
        _workerWait.WaitOne();
    }

Where the thread adding jobs now locks _workerWait and calls _workerWait.Set() when it's done adding jobs. This solution (seemingly) instantly starts processing jobs, and the delay is gone altogether.

My question is partly "Why does this happen?", granted that Thread.Sleep(int) can very well sleep for longer than you specify, and partly "How does the ManualResetEvent achieve this level of performance?".

EDIT: Since someone asked about the function that's queueing items, here it is, along with the full system as it stands at the moment.

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);
            }
        }
    }
}

解决方案

The events are kernel primitives provided by the OS/Kernel that's designed just for this sort of things. The kernel provides a boundary upon which you can guarantee atomic operations which is important for synchronization(Some atomicity can be done in user space too with hardware support).

In short, when a thread waits on an event it's put on a waiting list for that event and marked as non-runnable. When the event is signaled, the kernel wakes up the ones in the waiting list and marks them as runnable and they can continue to run. It's naturally a huge benefit that a thread can wake up immediately when the event is signalled, vs sleeping for a long time and recheck the condition every now and then.

Even one millisecond is a really really long time, you could have processed thousands of event in that time. Also the time resolution is traditionally 10ms, so sleeping less than 10ms usually just results in a 10ms sleep anyway. With an event, a thread can be woken up and scheduled immediately

这篇关于ManualResetEvent的对比了Thread.Sleep的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆