protected void QueueImageLoadingTask(IImageLoaderTask task) { int position = Interlocked.Increment(ref _currentPosition); var currentPendingTask = new PendingTask() { Position = position, ImageLoadingTask = task, FrameworkWrappingTask = CreateFrameworkTask(task) }; PendingTask similarRunningTask = null; lock (_pendingTasksLock) { similarRunningTask = PendingTasks.FirstOrDefault(t => t.ImageLoadingTask.Key == task.Key); if (similarRunningTask == null) { Interlocked.Increment(ref _statsTotalPending); PendingTasks.Add(currentPendingTask); } else { similarRunningTask.Position = position; } } if (similarRunningTask == null || !currentPendingTask.ImageLoadingTask.CanUseMemoryCache) { TakeFromPendingTasksAndRun(); } else { WaitForSimilarTaskFinished(currentPendingTask, similarRunningTask); } }
private async Task QueueTaskAsync(PendingTask pendingTask, bool scheduleOnThreadPool) { if (_currentlyRunning.Count >= MaxParallelTasks) { return; } if (!_currentlyRunning.TryAdd(pendingTask, 1)) { return; // If we can't add it it most likely means that it's already in } try { if (scheduleOnThreadPool) { await Task.Run(pendingTask.ImageLoadingTask.RunAsync).ConfigureAwait(false); } else { await pendingTask.ImageLoadingTask.RunAsync().ConfigureAwait(false); } } finally { byte dummy; if (!_currentlyRunning.TryRemove(pendingTask, out dummy)) { _logger.Error("WorkScheduler: Could not remove task from running tasks."); } } await RunAsync().ConfigureAwait(false); }
private void QueueAndGenerateImage(IImageLoaderTask task) { _logger.Debug(string.Format("Generating/retrieving image: {0}", task.GetKey())); int position = Interlocked.Increment(ref _currentPosition); var currentPendingTask = new PendingTask() { Position = position, ImageLoadingTask = task }; var alreadyRunningTaskForSameKey = FindSimilarPendingTask(task); if (alreadyRunningTaskForSameKey == null) { if (!AddTaskToPendingTasks(currentPendingTask)) { return; } } else { alreadyRunningTaskForSameKey.Position = position; } if (alreadyRunningTaskForSameKey == null || !currentPendingTask.ImageLoadingTask.CanUseMemoryCache()) { Run(currentPendingTask); } else { WaitForSimilarTask(currentPendingTask, alreadyRunningTaskForSameKey); } }
private void QueueAndGenerateImage(IImageLoaderTask task) { _logger.Debug(string.Format("Generating/retrieving image: {0}", task.GetKey())); int position = Interlocked.Increment(ref _currentPosition); var currentPendingTask = new PendingTask() { Position = position, ImageLoadingTask = task, FrameworkWrappingTask = CreateFrameworkTask(task) }; PendingTask alreadyRunningTaskForSameKey = null; lock (_pendingTasksLock) { alreadyRunningTaskForSameKey = FindSimilarPendingTask(task); if (alreadyRunningTaskForSameKey == null) { Interlocked.Increment(ref _statsTotalPending); _pendingTasks.Add(currentPendingTask); } else { alreadyRunningTaskForSameKey.Position = position; } } if (alreadyRunningTaskForSameKey == null || !currentPendingTask.ImageLoadingTask.CanUseMemoryCache()) { Run(currentPendingTask); } else { WaitForSimilarTask(currentPendingTask, alreadyRunningTaskForSameKey); } }
private void QueueAndGenerateImage(IImageLoaderTask task) { _logger.Debug(string.Format("Generating/retrieving image: {0}", task.GetKey())); var currentPendingTask = new PendingTask() { ImageLoadingTask = task }; PendingTask alreadyRunningTaskForSameKey = null; lock (_pauseWorkLock) { lock (_pendingTasksLock) { alreadyRunningTaskForSameKey = _pendingTasks.FirstOrDefault(t => t.ImageLoadingTask.GetKey() == task.GetKey() && (!t.ImageLoadingTask.IsCancelled)); if (alreadyRunningTaskForSameKey == null) { _pendingTasks.Add(currentPendingTask); } } } if (alreadyRunningTaskForSameKey == null || !currentPendingTask.ImageLoadingTask.CanUseMemoryCache()) { Run(currentPendingTask); } else { WaitForSimilarTask(currentPendingTask, alreadyRunningTaskForSameKey); } }
bool TryTakeNewTask() { Uri navigateTo; lock (syncRoot) { if (currentTask != null || browserState != BrowserState.Ready) { return(false); } for (; tasks.Count > 0 && currentTask == null;) { var task = tasks.Dequeue(); if (!CompletePromiseIfCancellationRequested(task)) { currentTask = task; } } if (currentTask == null) { return(false); } tracer.Info("taking new task {0}", currentTask); currentTask.cancellationRegistration = currentTask.cancellation.Register( OnTaskCancelled, useSynchronizationContext: false); currentTask.progressSink = currentTask.progress != null?currentTask.progress.CreateProgressSink() : null; navigateTo = currentTask.location; SetBroswerState(BrowserState.Busy); } downloaderFormNavigationTask = uiInvokeSynchronization.Invoke(() => downloaderForm.Navigate(navigateTo)); return(true); }
public void TearDown() { _taskScheduler.Dispose(); PendingTask.GetActivePeriodicTimersCount().Should().Be(0); PendingTask.GetActivePeriodicSlTimersCount().Should().Be(0); PendingTask.GetExecutingActionsCount().Should().Be(0); PendingTask.GetActiveTimersCount().Should().Be(0); }
protected void QueueImageLoadingTask(IImageLoaderTask task) { int position = Interlocked.Increment(ref _currentPosition); var currentPendingTask = new PendingTask() { Position = position, ImageLoadingTask = task, FrameworkWrappingTask = CreateFrameworkTask(task) }; if (task.IsCancelled || task.IsCompleted || ExitTasksEarly) { task?.Dispose(); return; } PendingTask similarRunningTask = null; lock (_pendingTasksLock) { if (!task.Parameters.Preload) { foreach (var pendingTask in PendingTasks.ToList()) // FMT: here we need a copy since cancelling will trigger them to be removed, hence collection is modified during enumeration { if (pendingTask.ImageLoadingTask != null && pendingTask.ImageLoadingTask.UsesSameNativeControl(task)) { pendingTask.ImageLoadingTask.CancelIfNeeded(); } } EvictStaleTasks(); } similarRunningTask = PendingTasks.FirstOrDefault(t => t.ImageLoadingTask.Key == task.Key); if (similarRunningTask == null) { Interlocked.Increment(ref _statsTotalPending); PendingTasks.Add(currentPendingTask); } else { similarRunningTask.Position = position; } } if (PauseWork) { return; } if (similarRunningTask == null || !currentPendingTask.ImageLoadingTask.CanUseMemoryCache) { TakeFromPendingTasksAndRun(); } else { WaitForSimilarTaskFinished(currentPendingTask, similarRunningTask); } }
public async Task ActiveTimerEndsTest() { PendingTask.GetActiveTimersCount().Should().Be(0); _taskScheduler.Schedule(() => { Thread.Sleep(100); }, 10); PendingTask.GetActiveTimersCount().Should().Be(1); await Task.Delay(200); PendingTask.GetActiveTimersCount().Should().Be(0); }
/// <summary> /// Enqueues the given task to this scheduler: It will be executed /// once all previous tasks have finished or failed. /// </summary> /// <param name="fn"></param> /// <param name="completionSource"></param> public void QueueTask(Action fn, TaskCompletionSource <int> completionSource) { lock (_syncRoot) { var pendingTask = new PendingTask(fn, completionSource); Task task = pendingTask.Task; EnqueueTask(pendingTask, task); StarTaskIfNecessary(); } }
bool CompletePromiseIfCancellationRequested(PendingTask task) { if (!task.cancellation.IsCancellationRequested) { return(false); } tracer.Info("completing task {0} with TaskCanceledException as its cancellation was requested", task); task.promise.SetException(new TaskCanceledException()); task.Dispose(); return(true); }
private void CollectMemoryAndThreadsUsage() { Metrics.Measure.Histogram.Update(Gen0Collections, GC.CollectionCount(0)); Metrics.Measure.Histogram.Update(Gen1Collections, GC.CollectionCount(1)); Metrics.Measure.Histogram.Update(Gen2Collections, GC.CollectionCount(2)); Metrics.Measure.Histogram.Update(GcTotalMemory, GC.GetTotalMemory(false)); Metrics.Measure.Histogram.Update(PendingTasks, TaskScheduler.GetGlobalScheduledOnceTasksCount()); Metrics.Measure.Histogram.Update(ExecutingTask, PendingTask.GetExecutingActionsCount()); Metrics.Measure.Histogram.Update(ActiveTimers, PendingTask.GetActiveTimersCount()); Metrics.Measure.Histogram.Update(ActivePeriodicTimers, PendingTask.GetActivePeriodicTimersCount()); Metrics.Measure.Histogram.Update(ActivePeriodicSlTimers, PendingTask.GetActivePeriodicSlTimersCount()); }
async Task <Stream> IDownloader.Download(DownloadParams downloadParams) { if (downloadParams.CacheMode == CacheMode.AllowCacheReading || downloadParams.CacheMode == CacheMode.DownloadFromCacheOnly) { var cachedValue = cache.GetValue(downloadParams.Location); if (cachedValue != null) { tracer.Info("found in cache content for location='{0}'", downloadParams.Location); return(cachedValue); } if (downloadParams.CacheMode == CacheMode.DownloadFromCacheOnly) { return(null); } } var task = new PendingTask() { location = downloadParams.Location, expectedMimeType = downloadParams.ExpectedMimeType, cancellation = downloadParams.Cancellation, progress = downloadParams.Progress, isLoginUrl = downloadParams.IsLoginUrl, stream = new MemoryStream(), promise = new TaskCompletionSource <Stream>(), }; lock (syncRoot) { tracer.Info("new task {0} added for location='{1}'", task, task.location); tasks.Enqueue(task); } TryTakeNewTask(); var stream = await task.promise.Task; if (stream != null) { bool setCache = true; if (downloadParams.AllowCacheWriting != null) { stream.Position = 0; setCache = downloadParams.AllowCacheWriting(stream); } if (setCache) { stream.Position = 0; await cache.SetValue(downloadParams.Location, stream); } stream.Position = 0; } return(stream); }
public void TestActionExecutionCounting() { using (var taskScheduler2 = new TaskScheduler(Mock.Of <IShamanLogger>())) { _taskScheduler.Schedule(() => { Thread.Sleep(100); }, 10); _taskScheduler.Schedule(() => { Thread.Sleep(100); }, 10); taskScheduler2.Schedule(() => { Thread.Sleep(100); }, 10); Thread.Sleep(20); // schedulers tasks triggers only in second PendingTask.GetExecutingActionsCount().Should().Be(3); } Thread.Sleep(100);// wait task ends }
public static string ToColor(this PendingTask pendingTask, Priority priority) { switch (priority) { case Priority.Urgent: return("#f00"); case Priority.High: return("#f80"); case Priority.Normal: return("#0c0"); case Priority.Low: return("#0f8"); default: return("transparent"); } }
void IViewEvents.OnAborted() { lock (syncRoot) { tracer.Info("OnAborted. current task={0}", currentTask); if (currentTask != null) { currentTask.promise.SetException(new TaskCanceledException()); currentTask.Dispose(); currentTask = null; } } ResetBrowser(); TryTakeNewTask(); }
protected async Task RunImageLoadingTaskAsync(PendingTask pendingTask) { var key = pendingTask.ImageLoadingTask.Key; lock (_pendingTasksLock) { if (RunningTasks.ContainsKey(key)) return; RunningTasks.Add(key, pendingTask); Interlocked.Increment(ref _statsTotalRunning); } try { if (Configuration.VerbosePerformanceLogging) { LogSchedulerStats(); var stopwatch = Stopwatch.StartNew(); await Task.Run(pendingTask.ImageLoadingTask.RunAsync).ConfigureAwait(false); stopwatch.Stop(); Logger.Debug( string.Format( "[PERFORMANCE] RunAsync - NetManagedThreadId: {0}, NativeThreadId: {1}, Execution: {2} ms, Key: {3}", Performance.GetCurrentManagedThreadId(), Performance.GetCurrentSystemThreadId(), stopwatch.Elapsed.Milliseconds, key)); } else { await Task.Run(pendingTask.ImageLoadingTask.RunAsync).ConfigureAwait(false); } } finally { lock (_pendingTasksLock) { RunningTasks.Remove(key); } pendingTask?.ImageLoadingTask?.Dispose(); await TakeFromPendingTasksAndRunAsync().ConfigureAwait(false); } }
public void AddPendingTask(PendingTask pendingTask) { if (pendingTask == null) { throw new NullReferenceException("Null Task Provided"); } if (!_shouldSchedule) { pendingTask.Invoke(); } else { _pendingTasks.Add(pendingTask); } }
public void TaskCountingDelayedTasksTest() { using (var taskScheduler2 = new TaskScheduler(Mock.Of <IShamanLogger>())) { _taskScheduler.Schedule(() => { Thread.Sleep(100); }, 10); _taskScheduler.Schedule(() => { Thread.Sleep(100); }, 10); _taskScheduler.Schedule(() => { Thread.Sleep(100); }, 10); _taskScheduler.Schedule(() => { Thread.Sleep(100); }, 10); PendingTask.GetActiveTimersCount().Should().Be(4); taskScheduler2.Schedule(() => { Thread.Sleep(100); }, 10); PendingTask.GetActiveTimersCount().Should().Be(5); } }
public static string EffortForDisplay(this PendingTask pendingTask) { var effort = ""; if (pendingTask.Status == Status.Completed) { if (pendingTask.StartDate.HasValue && pendingTask.CompletionDate.HasValue) { var ts = pendingTask.CompletionDate.Value - pendingTask.StartDate.Value; if (ts.Days <= 0) { return("Less than a day"); } effort = String.Format("{0} day(s)", ts.Days); } } return(effort); }
private async void WaitForSimilarTask(PendingTask currentPendingTask, PendingTask alreadyRunningTaskForSameKey) { string key = alreadyRunningTaskForSameKey.ImageLoadingTask.GetKey(); Action forceLoad = () => { lock (_pauseWorkLock) { lock (_pendingTasksLock) { _pendingTasks.Add(currentPendingTask); } } Run(currentPendingTask); }; if (alreadyRunningTaskForSameKey.FrameworkWrappingTask == null) { _logger.Debug(string.Format("No C# Task defined for key: {0}", key)); forceLoad(); return; } _logger.Debug(string.Format("Wait for similar request for key: {0}", key)); // This will wait for the pending task or if it is already finished then it will just pass await alreadyRunningTaskForSameKey.FrameworkWrappingTask.ConfigureAwait(false); // Now our image should be in the cache var cacheResult = await currentPendingTask.ImageLoadingTask.TryLoadingFromCacheAsync().ConfigureAwait(false); if (cacheResult != FFImageLoading.Cache.CacheResult.Found) { _logger.Debug(string.Format("Similar request finished but the image is not in the cache: {0}", key)); forceLoad(); } else { var task = currentPendingTask.ImageLoadingTask; if (task.Parameters.OnFinish != null) { task.Parameters.OnFinish(task); } task.Dispose(); } }
protected async void WaitForSimilarTaskFinished(PendingTask currentPendingTask, PendingTask taskForSimilarKey) { Interlocked.Increment(ref _statsTotalWaiting); if ((taskForSimilarKey?.FrameworkWrappingTask == null) || taskForSimilarKey.FrameworkWrappingTask.IsCanceled || taskForSimilarKey.FrameworkWrappingTask.IsFaulted) { lock (_pendingTasksLock) { Interlocked.Increment(ref _statsTotalPending); PendingTasks.Add(currentPendingTask); } TakeFromPendingTasksAndRun(); return; } Logger.Debug(string.Format("Wait for similar request for key: {0}", taskForSimilarKey.ImageLoadingTask.Key)); await taskForSimilarKey.FrameworkWrappingTask.ConfigureAwait(false); if ((currentPendingTask?.ImageLoadingTask == null) || currentPendingTask.ImageLoadingTask.IsCancelled) return; // Now our image should be in the cache var cacheFound = await currentPendingTask.ImageLoadingTask.TryLoadFromMemoryCacheAsync().ConfigureAwait(false); if (!cacheFound) { if ((currentPendingTask?.ImageLoadingTask == null) || currentPendingTask.ImageLoadingTask.IsCancelled) return; lock (_pendingTasksLock) { Interlocked.Increment(ref _statsTotalPending); PendingTasks.Add(currentPendingTask); } TakeFromPendingTasksAndRun(); } else { currentPendingTask?.ImageLoadingTask?.Dispose(); } }
public void Handle(TaskCreatedEvent message) { var task = new PendingTask { TaskId = message.TaskId, Title = message.Title, Description = message.Description, DueDate = message.DueDate, Priority = message.Priority, Status = Status.ToDo // Default status for new tasks (by design) }; using (var context = new TaskContext()) { context.PendingTasks.Add(task); context.SaveChanges(); } }
public void TaskCountingPeriodShortLivingTasksTest() { using (var taskScheduler2 = new TaskScheduler(Mock.Of <IShamanLogger>())) { _taskScheduler.ScheduleOnInterval(() => { Thread.Sleep(100); }, 10, 10, true); _taskScheduler.ScheduleOnInterval(() => { Thread.Sleep(100); }, 10, 10, true); _taskScheduler.ScheduleOnInterval(() => { Thread.Sleep(100); }, 10, 10, true); _taskScheduler.ScheduleOnInterval(() => { Thread.Sleep(100); }, 10, 10, true); PendingTask.GetActivePeriodicTimersCount().Should().Be(TaskSchedulerInternalPeriodicTimersCount); PendingTask.GetActivePeriodicSlTimersCount().Should().Be(4); taskScheduler2.ScheduleOnInterval(() => { Thread.Sleep(100); }, 10, 10, true); PendingTask.GetActivePeriodicTimersCount().Should().Be(TaskSchedulerInternalPeriodicTimersCount); PendingTask.GetActivePeriodicSlTimersCount().Should().Be(5); } }
private bool AddTaskToPendingTasks(PendingTask task) { if (!_pendingTasks.TryAdd(task.ImageLoadingTask.GetKey(), task)) { _logger.Error("Unable to schedule image task: task cannot be added to pending tasks queue."); return(false); } // Try adding the task by raw key, since many tasks can share the same raw key this may fail string rawKey = task.ImageLoadingTask.GetKey(raw: true); if (!_pendingTasksByRawKey.TryAdd(rawKey, task)) { _logger.Debug("There is already a task in pendingTasksByRawKey with this raw key."); } return(true); }
void IViewModel.OnFormSubmitted(IReadOnlyList <KeyValuePair <string, string> > values) { lock (syncRoot) { tracer.Info("OnFormSubmitted. current task={0}", currentTask); if (currentTask is UploadFormTask uploadFormTask) { uploadFormTask.promise.SetResult(values); currentTask.Dispose(); currentTask = null; } else { return; } } ResetBrowser(); TryTakeNewTask(); }
public async Task TestPendingTaskStopping() { _loggerMock.Setup(c => c.Error(It.Is <string>(v => v.Contains("SHORT-LIVING")))); var counter = 0; try { PendingTask.DurationMonitoringTime(TimeSpan.FromMilliseconds(200)); var task = _taskScheduler.ScheduleOnInterval(() => counter++, 0, 100, true); await Task.Delay(500); _loggerMock.Verify(c => c.Error(It.Is <string>(v => v.Contains("SHORT-LIVING"))), Times.Once); } finally { PendingTask.DurationMonitoringTime(TimeSpan.FromMinutes(15)); } counter.Should().Be(2); }
private async void Run(PendingTask pendingTask) { if (MaxParallelTasks <= 0) { pendingTask.FrameworkWrappingTask = pendingTask.ImageLoadingTask.RunAsync(); // FMT: threadpool will limit concurrent work await pendingTask.FrameworkWrappingTask.ConfigureAwait(false); return; } var tcs = new TaskCompletionSource <bool>(); var successCallback = pendingTask.ImageLoadingTask.Parameters.OnSuccess; pendingTask.ImageLoadingTask.Parameters.Success((size, result) => { tcs.TrySetResult(true); if (successCallback != null) { successCallback(size, result); } }); var finishCallback = pendingTask.ImageLoadingTask.Parameters.OnFinish; pendingTask.ImageLoadingTask.Parameters.Finish(sw => { tcs.TrySetResult(false); if (finishCallback != null) { finishCallback(sw); } }); pendingTask.FrameworkWrappingTask = tcs.Task; await RunAsync().ConfigureAwait(false); // FMT: we limit concurrent work using MaxParallelTasks }
/// <summary> /// Constructors accepts the IP and port to listen for requests /// on and the instance that will process requests. /// </summary> public KernelWebHost(IWebRequestHandler handler, string listenIP, int listenPort) { ListenIP = IPAddress.Parse(listenIP); ListenPort = listenPort; Handler = handler; _server = new TcpListener(ListenIP, ListenPort); _server.Start(); // start infinite continuation of checking the web server #if DISABLE_WEB_TASK #warning Web Server Task is DISABLED!!!! #else _pendingTask = new PendingTask() { Parent = this }; #endif /* #warning I hate this thread. * new SingleThread() * { * Name = "Restart web host scheduler", * Step = () => * { * if ((DateTime.Now - _pendingTask.LastRan).TotalSeconds > 2.5) * { * Session.UserSession.Current.Console.Add("Had to restart scheduler"); * _pendingTask.ScheduleTask(); * } * Thread.Sleep(2500); * }, * SleepAfterStep = true * } * .Start(); */ }
void OnTaskCancelled() { lock (syncRoot) { tracer.Info("task cancelled callback received"); var cpy = tasks.ToArray(); tasks.Clear(); foreach (var task in cpy) { if (!CompletePromiseIfCancellationRequested(task)) { tasks.Enqueue(task); } } if (currentTask != null) { if (CompletePromiseIfCancellationRequested(currentTask)) { currentTask = null; } } } }
private async void Run(PendingTask pendingTask) { if (MaxParallelTasks <= 0) { pendingTask.FrameworkWrappingTask = pendingTask.ImageLoadingTask.RunAsync(); // FMT: threadpool will limit concurrent work await pendingTask.FrameworkWrappingTask.ConfigureAwait(false); return; } var tcs = new TaskCompletionSource<bool>(); var successCallback = pendingTask.ImageLoadingTask.Parameters.OnSuccess; pendingTask.ImageLoadingTask.Parameters.Success((size, result) => { tcs.TrySetResult(true); if (successCallback != null) successCallback(size, result); }); var finishCallback = pendingTask.ImageLoadingTask.Parameters.OnFinish; pendingTask.ImageLoadingTask.Parameters.Finish(sw => { tcs.TrySetResult(false); if (finishCallback != null) finishCallback(sw); }); pendingTask.FrameworkWrappingTask = tcs.Task; await RunAsync().ConfigureAwait(false); // FMT: we limit concurrent work using MaxParallelTasks }
private async void WaitForSimilarTask(PendingTask currentPendingTask, PendingTask alreadyRunningTaskForSameKey) { string key = alreadyRunningTaskForSameKey.ImageLoadingTask.GetKey(); Action forceLoad = () => { lock (_pauseWorkLock) { lock(_pendingTasksLock) { _pendingTasks.Add(currentPendingTask); } } Run(currentPendingTask); }; if (alreadyRunningTaskForSameKey.FrameworkWrappingTask == null) { _logger.Debug(string.Format("No C# Task defined for key: {0}", key)); forceLoad(); return; } _logger.Debug(string.Format("Wait for similar request for key: {0}", key)); // This will wait for the pending task or if it is already finished then it will just pass await alreadyRunningTaskForSameKey.FrameworkWrappingTask.ConfigureAwait(false); // Now our image should be in the cache var cacheResult = await currentPendingTask.ImageLoadingTask.TryLoadingFromCacheAsync().ConfigureAwait(false); if (cacheResult != FFImageLoading.Cache.CacheResult.Found) { _logger.Debug(string.Format("Similar request finished but the image is not in the cache: {0}", key)); forceLoad(); } else { var task = currentPendingTask.ImageLoadingTask; if (task.Parameters.OnFinish != null) task.Parameters.OnFinish(task); task.Dispose(); } }
private void QueueAndGenerateImage(IImageLoaderTask task) { _logger.Debug(string.Format("Generating/retrieving image: {0}", task.GetKey())); var currentPendingTask = new PendingTask() { ImageLoadingTask = task }; PendingTask alreadyRunningTaskForSameKey = null; lock (_pauseWorkLock) { lock (_pendingTasksLock) { alreadyRunningTaskForSameKey = _pendingTasks.FirstOrDefault(t => t.ImageLoadingTask.GetKey() == task.GetKey() && (!t.ImageLoadingTask.IsCancelled)); if (alreadyRunningTaskForSameKey == null) _pendingTasks.Add(currentPendingTask); } } if (alreadyRunningTaskForSameKey == null || !currentPendingTask.ImageLoadingTask.CanUseMemoryCache()) { Run(currentPendingTask); } else { WaitForSimilarTask(currentPendingTask, alreadyRunningTaskForSameKey); } }
private async void Run(PendingTask pendingTask) { await RunAsync().ConfigureAwait(false); // FMT: we limit concurrent work using MaxParallelTasks }
private async Task QueueTaskAsync(PendingTask pendingTask, bool scheduleOnThreadPool) { lock (_pendingTasksLock) { if (_currentlyRunning.Count >= _maxParallelTasks) return; } string key = pendingTask.ImageLoadingTask.GetKey(); try { PendingTask alreadyRunningTask = null; lock (_pendingTasksLock) { if (!_currentlyRunning.ContainsKey(key)) { _currentlyRunning.Add(key, pendingTask); Interlocked.Increment(ref _statsTotalRunning); } else { alreadyRunningTask = _currentlyRunning[key]; // duplicate - return if (pendingTask == alreadyRunningTask) return; } } if (alreadyRunningTask != null) { WaitForSimilarTask(pendingTask, alreadyRunningTask); return; } if (_verbosePerformanceLogging) { Stopwatch stopwatch = Stopwatch.StartNew(); if (scheduleOnThreadPool) { await Task.Run(pendingTask.ImageLoadingTask.RunAsync).ConfigureAwait(false); } else { await pendingTask.ImageLoadingTask.RunAsync().ConfigureAwait(false); } stopwatch.Stop(); LogSchedulerStats(); _logger.Debug(string.Format("[PERFORMANCE] RunAsync - NetManagedThreadId: {0}, NativeThreadId: {1}, Execution: {2} ms, ThreadPool: {3}, Key: {4}", _performance.GetCurrentManagedThreadId(), _performance.GetCurrentSystemThreadId(), stopwatch.Elapsed.Milliseconds, scheduleOnThreadPool, key)); } else { if (scheduleOnThreadPool) { await Task.Run(pendingTask.ImageLoadingTask.RunAsync).ConfigureAwait(false); } else { await pendingTask.ImageLoadingTask.RunAsync().ConfigureAwait(false); } } } finally { lock (_pendingTasksLock) { _currentlyRunning.Remove(key); } await RunAsync().ConfigureAwait(false); } }
protected void QueueImageLoadingTask(IImageLoaderTask task) { int position = Interlocked.Increment(ref _currentPosition); var currentPendingTask = new PendingTask() { Position = position, ImageLoadingTask = task, FrameworkWrappingTask = CreateFrameworkTask(task) }; if (task.IsCancelled || task.IsCompleted || ExitTasksEarly) { task?.Dispose(); return; } PendingTask similarRunningTask = null; lock (_pendingTasksLock) { if (!task.Parameters.Preload) { foreach (var pendingTask in PendingTasks.ToList()) // FMT: here we need a copy since cancelling will trigger them to be removed, hence collection is modified during enumeration { if (pendingTask.ImageLoadingTask != null && pendingTask.ImageLoadingTask.UsesSameNativeControl(task)) pendingTask.ImageLoadingTask.CancelIfNeeded(); } EvictStaleTasks(); } similarRunningTask = PendingTasks.FirstOrDefault(t => t.ImageLoadingTask.Key == task.Key); if (similarRunningTask == null) { Interlocked.Increment(ref _statsTotalPending); PendingTasks.Add(currentPendingTask); } else { similarRunningTask.Position = position; } } if (PauseWork) return; if (similarRunningTask == null || !currentPendingTask.ImageLoadingTask.CanUseMemoryCache) { TakeFromPendingTasksAndRun(); } else { WaitForSimilarTaskFinished(currentPendingTask, similarRunningTask); } }
protected async void WaitForSimilarTaskFinished(PendingTask currentPendingTask, PendingTask taskForSimilarKey) { Interlocked.Increment(ref _statsTotalWaiting); if (taskForSimilarKey.FrameworkWrappingTask == null) { lock (_pendingTasksLock) { Interlocked.Increment(ref _statsTotalPending); PendingTasks.Add(currentPendingTask); } TakeFromPendingTasksAndRun(); return; } Logger.Debug(string.Format("Wait for similar request for key: {0}", taskForSimilarKey.ImageLoadingTask.Key)); await taskForSimilarKey.FrameworkWrappingTask.ConfigureAwait(false); // Now our image should be in the cache var cacheFound = await currentPendingTask.ImageLoadingTask.TryLoadFromMemoryCacheAsync().ConfigureAwait(false); if (!cacheFound) { lock (_pendingTasksLock) { Interlocked.Increment(ref _statsTotalPending); PendingTasks.Add(currentPendingTask); } TakeFromPendingTasksAndRun(); return; } else { currentPendingTask?.ImageLoadingTask?.Dispose(); } }
protected async Task RunImageLoadingTaskAsync(PendingTask pendingTask, bool scheduleOnThreadPool) { var key = pendingTask.ImageLoadingTask.Key; lock (_pendingTasksLock) { if (RunningTasks.ContainsKey(key)) return; RunningTasks.Add(key, pendingTask); Interlocked.Increment(ref _statsTotalRunning); } try { if (Configuration.VerbosePerformanceLogging) { LogSchedulerStats(); Stopwatch stopwatch = Stopwatch.StartNew(); if (scheduleOnThreadPool) { await Task.Run(pendingTask.ImageLoadingTask.RunAsync).ConfigureAwait(false); } else { await pendingTask.ImageLoadingTask.RunAsync().ConfigureAwait(false); } stopwatch.Stop(); Logger.Debug(string.Format("[PERFORMANCE] RunAsync - NetManagedThreadId: {0}, NativeThreadId: {1}, Execution: {2} ms, ThreadPool: {3}, Key: {4}", Performance.GetCurrentManagedThreadId(), Performance.GetCurrentSystemThreadId(), stopwatch.Elapsed.Milliseconds, scheduleOnThreadPool, key)); } else { if (scheduleOnThreadPool) { await Task.Run(pendingTask.ImageLoadingTask.RunAsync).ConfigureAwait(false); } else { await pendingTask.ImageLoadingTask.RunAsync().ConfigureAwait(false); } } } finally { lock (_pendingTasksLock) { RunningTasks.Remove(key); } pendingTask?.ImageLoadingTask?.Dispose(); await TakeFromPendingTasksAndRunAsync().ConfigureAwait(false); } }