private WeightedWorkScheduler() { _newWork = new ConcurrentQueue <WorkItem>(); _newWorkEvent = new AutoResetEvent(false); var work = new List <WorkQueue>(); var queueManager = new Thread(() => { var workersCount = Configuration.Config.GetInt("data-feed-workers-count", Environment.ProcessorCount); MaxWorkWeight = Configuration.Config.GetInt("data-feed-max-work-weight", 400); Logging.Log.Trace($"WeightedWorkScheduler(): will use {workersCount} workers and MaxWorkWeight is {MaxWorkWeight}"); for (var i = 0; i < workersCount; i++) { var workQueue = new WorkQueue(); work.Add(workQueue); var thread = new Thread(() => WorkerThread(workQueue, _newWork, _newWorkEvent)) { IsBackground = true, Priority = ThreadPriority.Lowest, Name = $"WeightedWorkThread{i}" }; thread.Start(); } // make sure that the WorkQueue are kept sorted and the weights up to date while (true) { Thread.Sleep(TimeSpan.FromMilliseconds(1)); foreach (var queue in work) { queue.Sort(); } } }) { IsBackground = true, Name = "WeightedWorkManager" }; queueManager.Start(); }
/// <summary> /// This is the worker thread loop. /// It will first try to take a work item from the new work queue else will check his own queue. /// </summary> private static void WorkerThread(WorkQueue workQueue, ConcurrentQueue <WorkItem> newWork, AutoResetEvent newWorkEvent) { var waitHandles = new WaitHandle[] { workQueue.WorkAvailableEvent, newWorkEvent }; while (true) { WorkItem workItem; if (!newWork.TryDequeue(out workItem)) { workItem = workQueue.Get(); if (workItem == null) { // no work to do, lets sleep and try again WaitHandle.WaitAny(waitHandles, 100); continue; } } else { workQueue.Add(workItem); } try { if (!workItem.Work(WorkBatchSize)) { workQueue.Remove(workItem); } } catch (Exception exception) { workQueue.Remove(workItem); Logging.Log.Error(exception); } } }