From b286a0b0f1fcdb511d2dbb8886039cfb0182c89b Mon Sep 17 00:00:00 2001 From: Jake Mannens Date: Fri, 1 Sep 2023 13:03:57 +1000 Subject: Merged OCR functionality --- Util.cs | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) (limited to 'Util.cs') diff --git a/Util.cs b/Util.cs index 31a2e84..6af6c81 100644 --- a/Util.cs +++ b/Util.cs @@ -18,4 +18,103 @@ public static class Extensions { double n = x / Math.Pow(10, exp / 3 * 3); return $"{Math.Round(n, 2 - (exp % 3))} {suffix}B"; } + + public static string ToStringHumanReadable(this TimeSpan t) { + if(t.TotalMilliseconds < 1000) + return string.Format("{0:0}ms", t.TotalMilliseconds); + if(t.TotalSeconds < 60) + return string.Format("{0:0.00}s", t.TotalSeconds); + if(t.TotalMinutes < 60) + return string.Format("{0:0}m{0:0}s", t.TotalMinutes, t.Seconds); + if(t.TotalHours < 24) + return string.Format("{0:0}h{0:0}m", t.TotalHours, t.Minutes); + return string.Format("{0:0.00}d", t.TotalDays); + } +} + +public class LimitedConcurrencyTaskScheduler : TaskScheduler { + public sealed override int MaximumConcurrencyLevel => + maxConcurrency; + + private int maxConcurrency; + + [ThreadStatic] + private static bool threadIsProcessingItems; + + private readonly LinkedList tasks = new(); + + private int delegatesQueuedOrRunning = 0; + + public LimitedConcurrencyTaskScheduler() { + maxConcurrency = Environment.ProcessorCount; + } + + public LimitedConcurrencyTaskScheduler(int maxConcurrency) { + if(maxConcurrency < 1) + throw new ArgumentOutOfRangeException("maxConcurrency must be greater than 0"); + this.maxConcurrency = (int) maxConcurrency; + } + + protected sealed override void QueueTask(Task task) { + lock(tasks) { + tasks.AddLast(task); + if(delegatesQueuedOrRunning < maxConcurrency) { + delegatesQueuedOrRunning++; + NotifyThreadPoolOfPendingWork(); + } + } + } + + private void NotifyThreadPoolOfPendingWork() { + ThreadPool.UnsafeQueueUserWorkItem(_ => { + threadIsProcessingItems = true; + try { + while(true) { + Task item; + lock(tasks) { + if(tasks.Count == 0) { + delegatesQueuedOrRunning--; + break; + } else { + item = tasks.First.Value; + tasks.RemoveFirst(); + } + } + TryExecuteTask(item); + } + } finally { + threadIsProcessingItems = false; + } + }, null); + } + + protected sealed override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) { + if(!threadIsProcessingItems) + return false; + + if(taskWasPreviouslyQueued) + return TryDequeue(task) ? TryExecuteTask(task) : false; + else + return TryExecuteTask(task); + } + + protected sealed override bool TryDequeue(Task task) { + lock(tasks) { + return tasks.Remove(task); + } + } + + protected sealed override IEnumerable GetScheduledTasks() { + bool lockTaken = false; + try { + Monitor.TryEnter(tasks, ref lockTaken); + if(lockTaken) + return tasks; + else + throw new NotSupportedException(); + } finally { + if(lockTaken) + Monitor.Exit(tasks); + } + } } -- cgit v1.3