I implementata in fondo thread di elaborazione, dove Jobs
è un Queue<T>
:ManualResetEvent vs Thread.Sleep
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.
}
}
}
Questo ha prodotto un ritardo notevole tra quando i processi venivano inseriti e quando sono stati effettivamente cominciano ad essere run (batch i lavori sono inseriti in una sola volta, e ogni lavoro è unico [relativamente] piccolo.) il ritardo non è stato un grande affare, ma ho avuto modo di pensare al problema, e ha fatto la seguente modifica:
static ManualResetEvent _workerWait = new ManualResetEvent(false);
// ...
if (job == null)
{
lock (_workerWait)
{
_workerWait.Reset();
}
_workerWait.WaitOne();
}
Dove il thread l'aggiunta di lavori ora blocca _workerWait
e chiama _workerWait.Set()
quando ha terminato di aggiungere lavori. Questa soluzione (apparentemente) inizia immediatamente a elaborare i lavori, e il ritardo è scomparso del tutto.
la mia domanda è in parte "Perché accade questo?", Concesso che Thread.Sleep(int)
può benissimo dormire per più di si specifica, e in parte "Come fa il ManualResetEvent
raggiungere questo livello di prestazioni?".
EDIT: Poiché qualcuno ha chiesto circa la funzione che è in coda articoli, eccola, insieme con l'intero sistema così com'è al momento.
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);
}
}
}
}
Informazioni più recenti: la risoluzione minima di 10 ms è un XP e prima cosa il sistema operativo utilizzava incrementi statici di 10 ms per la pianificazione. Penso che Vista, e so che Win7 lo fa, usa una fetta di tempo dinamica "senza tick". Con Win7, posso avviare un timer ad alta risoluzione, emettere un sonno (1) e il tempo è estremamente vicino a 1 ms, a volte inferiore a. – Bengie