次のバックグラウンド処理スレッドを実装しました。ここ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);
}
}
}
}