public void SetExitTasksEarly(bool exitTasksEarly) { if (ExitTasksEarly == exitTasksEarly) { return; } ExitTasksEarly = exitTasksEarly; if (exitTasksEarly) { Logger.Debug("ExitTasksEarly enabled."); lock (_lock) { foreach (var task in PendingTasks) { task?.Cancel(); } PendingTasks.Clear(); foreach (var task in SimilarTasks) { task?.Cancel(); } SimilarTasks.Clear(); } } else { Logger.Debug("ExitTasksEarly disabled."); } }
public static bool SavePendingTask(string userName, string task, string link) { bool exe = false; DateTime date = DateTime.Now; int userID = UserRepository.RetrieveUserIdByUserName(userName); try { if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(task) || string.IsNullOrEmpty(link)) { return(exe); } using (AppDb context = new AppDb()) { PendingTasks data = new PendingTasks() { UserId = userID, Task = task, Link = link, Date = date, Pending = false }; context.PendingTasks.Add(data); context.SaveChanges(); exe = true; } } catch (Exception ex) { throw ex; } return(exe); }
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); } }
public void SetExitTasksEarly(bool exitTasksEarly) { if (ExitTasksEarly == exitTasksEarly) return; ExitTasksEarly = exitTasksEarly; if (exitTasksEarly) { Logger.Debug("ExitTasksEarly enabled."); lock (_pendingTasksLock) { foreach (var task in PendingTasks.ToList()) // FMT: here we need a copy since cancelling will trigger them to be removed, hence collection is modified during enumeration task.ImageLoadingTask.Cancel(); PendingTasks.Clear(); } } else { Logger.Debug("ExitTasksEarly disabled."); } }
public void SetPauseWork(bool pauseWork) { if (_pauseWork == pauseWork) { return; } _pauseWork = pauseWork; if (pauseWork) { Logger.Debug("SetPauseWork paused."); lock (_pendingTasksLock) { foreach (var task in PendingTasks.ToList()) // FMT: here we need a copy since cancelling will trigger them to be removed, hence collection is modified during enumeration { task.ImageLoadingTask.Cancel(); } PendingTasks.Clear(); } } if (!pauseWork) { Logger.Debug("SetPauseWork released."); } }
private void UpdateTaskAssignments() { lock (Host) { for (int i = 0; i < PendingTasks.Count; i++) { if (AvailableClients.Count > 0) { var task = PendingTasks[0]; IRemoteXTMF previousHost = null; if (PreferPreviousClient && PreviousTaskAssignments.TryGetValue(task.TaskName, out previousHost) && AvailableClients.Contains(previousHost)) { RemoveClient(previousHost); task.Client = previousHost; } else { task.Client = AvailableClients.Pop(); } task.TaskNumber = GetTaskNumber(); PreviousTaskAssignments[task.TaskName] = task.Client; ExecutingTasks.Add(task); // clean up PendingTasks.RemoveAt(0); // fire the message to start processing task.Client.SendCustomMessage(task, DistributionDataChannel); } else { return; } } } }
public virtual void RemovePendingTask(IImageLoaderTask task) { lock (_pendingTasksLock) { PendingTasks.RemoveAll(p => p.ImageLoadingTask == task); } }
public virtual void Cancel(Func<IImageLoaderTask, bool> predicate) { lock (_pendingTasksLock) { foreach (var task in PendingTasks.Where(p => predicate(p.ImageLoadingTask)).ToList()) // FMT: here we need a copy since cancelling will trigger them to be removed, hence collection is modified during enumeration task.ImageLoadingTask.Cancel(); } }
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 void QueueImageLoadingTask(IImageLoaderTask task) { if (task.IsCancelled || task.IsCompleted || ExitTasksEarly) { if (!task.IsCompleted) { task.TryDispose(); } return; } IImageLoaderTask similarRunningTask = null; similarRunningTask = PendingTasks.FirstOrDefaultByRawKey(task.KeyRaw); if (similarRunningTask == null) { Interlocked.Increment(ref _statsTotalPending); Enqueue(task); } else { if (task.Parameters.Priority.HasValue && (!similarRunningTask.Parameters.Priority.HasValue || task.Parameters.Priority.Value > similarRunningTask.Parameters.Priority.Value)) { similarRunningTask.Parameters.WithPriority(task.Parameters.Priority.Value); PendingTasks.TryUpdatePriority(similarRunningTask, task.Parameters.Priority.Value); } if (task.Parameters.OnDownloadProgress != null) { var similarTaskOnDownloadProgress = similarRunningTask.Parameters.OnDownloadProgress; similarRunningTask.Parameters.DownloadProgress((DownloadProgress obj) => { similarTaskOnDownloadProgress?.Invoke(obj); task.Parameters.OnDownloadProgress(obj); }); } } if (PauseWork) { return; } if (similarRunningTask == null || !task.CanUseMemoryCache) { TakeFromPendingTasksAndRun(); } else { Interlocked.Increment(ref _statsTotalWaiting); Logger.Debug(string.Format("Wait for similar request for key: {0}", task.Key)); SimilarTasks.Add(task); } }
public virtual void RemovePendingTask(IImageLoaderTask task) { if (task != null) { lock (_lock) { PendingTasks.TryRemove(task); SimilarTasks.Remove(task); } } }
public virtual void Cancel(Func <IImageLoaderTask, bool> predicate) { lock (_lock) { foreach (var task in PendingTasks.Where(p => predicate(p))) { task?.Cancel(); } SimilarTasks.RemoveAll(predicate); } }
protected void QueueImageLoadingTask(IImageLoaderTask task) { if (task.IsCancelled || task.IsCompleted || ExitTasksEarly) { if (!task.IsCompleted) { task.TryDispose(); } return; } IImageLoaderTask?similarRunningTask = null; similarRunningTask = PendingTasks.FirstOrDefaultByRawKey(task.KeyRaw); if (similarRunningTask == null) { Interlocked.Increment(ref _statsTotalPending); Enqueue(task); } else { if (task.Priority.HasValue && (!similarRunningTask.Priority.HasValue || task.Priority.Value > similarRunningTask.Priority.Value)) { similarRunningTask.Priority = task.Priority.Value; PendingTasks.TryUpdatePriority(similarRunningTask, task.Priority.Value); } #if LATER similarRunningTask.ImageSource.DownloadProgress += (sender, args) => task.ImageSource.RaiseDownloadProgress(args); #endif } if (PauseWork) { return; } if (similarRunningTask == null || !task.CanUseMemoryCache) { TakeFromPendingTasksAndRun(); } else { Interlocked.Increment(ref _statsTotalWaiting); _imageLoader.Logger?.Debug($"Wait for similar request for key: {task.Key}"); SimilarTasks.Add(task); } }
public void AddTask(string taskName) { lock (Host) { PendingTasks.Add( new ExecutingTask() { Client = null, Complete = false, TaskName = taskName }); } UpdateTaskAssignments(); }
protected async Task TakeFromPendingTasksAndRunAsync() { Dictionary <string, PendingTask> tasksToRun = null; lock (_pendingTasksLock) { if (RunningTasks.Count >= MaxParallelTasks) { return; } int numberOfTasks = MaxParallelTasks - RunningTasks.Count; tasksToRun = new Dictionary <string, PendingTask>(); foreach (var task in PendingTasks.Where(t => !t.ImageLoadingTask.IsCancelled && !t.ImageLoadingTask.IsCompleted) .OrderByDescending(t => t.ImageLoadingTask.Parameters.Priority ?? GetDefaultPriority(t.ImageLoadingTask.Parameters.Source)) .ThenBy(t => t.Position)) { // We don't want to load, at the same time, images that have same key or same raw key at the same time // This way we prevent concurrent downloads and benefit from caches string rawKey = task.ImageLoadingTask.KeyRaw; if (RunningTasks.ContainsKey(rawKey) || tasksToRun.ContainsKey(rawKey)) { continue; } tasksToRun.Add(rawKey, task); if (tasksToRun.Count == numberOfTasks) { break; } } } if (tasksToRun != null && tasksToRun.Count > 0) { if (tasksToRun.Count == 1) { await RunImageLoadingTaskAsync(tasksToRun.Values.First(), false).ConfigureAwait(false); } else { var tasks = tasksToRun.Select(p => RunImageLoadingTaskAsync(p.Value, true)); await Task.WhenAny(tasks).ConfigureAwait(false); } } }
protected virtual void EvictStaleTasks() { lock (_pendingTasksLock) { var toRemove = PendingTasks.Where(v => v.FrameworkWrappingTask == null || v.ImageLoadingTask == null || v.ImageLoadingTask.IsCancelled || v.ImageLoadingTask.IsCompleted) .ToList(); foreach (var task in toRemove) { task?.ImageLoadingTask?.Dispose(); PendingTasks.Remove(task); } } }
public virtual void Cancel(Func <IImageLoaderTask, bool> predicate) { lock (_similarTasksLock) { foreach (var task in PendingTasks.Where(p => predicate(p))) { task?.Cancel(); } var items = SimilarTasks.Where(v => predicate(v)).ToList(); foreach (var item in items) { SimilarTasks.Remove(item); } } }
private void SpinAwait() { while (!disposing) { try { WaitForAvailableThread(); if (disposing) { return; } if (PendingTasks.Count > 0) { AbortableTask action = PendingTasks[0]; try { action.Task.Start(TaskFactory.Scheduler); Tasks.Add(action); } catch (System.Exception ex1) { if (OnThreadException != null) { OnThreadException.Invoke(this, ex1, action); } else { throw; } } PendingTasks.Remove(action); } } catch (System.Exception ex0) { if (OnThreadException != null) { OnThreadException.Invoke(this, ex0); } else { throw; } } System.Threading.Thread.Sleep(20); } }
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(); } }
/// <summary> /// Starts the <see cref="AbortableTask">Task</see> using <see cref="TaskManager.TaskFactory">TaskFactory</see> /// and adds it to the <see cref="TaskManager.Tasks">Tasks</see> collection or the /// <see cref="TaskManager.PendingTasks">PendingTasks</see> collection if no threads are available. /// </summary> /// <param name="task"></param> public void StartTask(AbortableTask task) { if (MaximumConcurrency <= RunningTasks.Count()) { PendingTasks.Add(task); } else { Tasks.Add(task); if (TaskFactory.Scheduler == null) { task.Task.Start(); } else { task.Task.Start(TaskFactory.Scheduler); } } }
public void SetPauseWork(bool pauseWork, bool cancelExisting = false) { if (PauseWork == pauseWork) { return; } if (cancelExisting) { lock (_lock) { foreach (var task in PendingTasks) { task?.Cancel(); } PendingTasks.Clear(); foreach (var task in SimilarTasks) { task?.Cancel(); } SimilarTasks.Clear(); } } PauseWork = pauseWork; if (pauseWork) { Logger.Debug("SetPauseWork enabled."); } else { Logger.Debug("SetPauseWork disabled."); TakeFromPendingTasksAndRun(); } }
public virtual async void LoadImage(IImageLoaderTask task) { Interlocked.Increment(ref _loadCount); EvictStaleTasks(); if (Configuration.VerbosePerformanceLogging && (_loadCount % 10) == 0) { LogSchedulerStats(); } if (task?.Parameters?.Source != ImageSource.Stream && string.IsNullOrWhiteSpace(task?.Parameters?.Path)) { Logger.Debug("ImageService: null path ignored"); task?.Dispose(); return; } if (task == null) { return; } if (task.IsCancelled || task.IsCompleted) { task?.Dispose(); return; } if (task.Parameters.DelayInMs != null && task.Parameters.DelayInMs > 0) { await Task.Delay(task.Parameters.DelayInMs.Value).ConfigureAwait(false); } // If we have the image in memory then it's pointless to schedule the job: just display it straight away if (task.CanUseMemoryCache) { if (await task.TryLoadFromMemoryCacheAsync().ConfigureAwait(false)) { Interlocked.Increment(ref _statsTotalMemoryCacheHits); task?.Dispose(); return; } } _dispatch = _dispatch.ContinueWith(t => { try { EvictStaleTasks(); if (task.IsCancelled || task.IsCompleted) { task?.Dispose(); return; } if (!task.Parameters.Preload) { lock (_pendingTasksLock) { 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(); } } } } if (task.IsCancelled || _pauseWork) { task?.Dispose(); return; } QueueImageLoadingTask(task); } catch (Exception ex) { Logger.Error(string.Format("Image loaded failed: {0}", task?.Key), ex); } }); }
protected async Task TakeFromPendingTasksAndRunAsync() { if (PendingTasks.Count == 0) { return; } Dictionary <string, IImageLoaderTask> tasksToRun = null; int preloadOrUrlTasksCount = 0; int urlTasksCount = 0; int preloadTasksCount = 0; lock (_lock) { if (RunningTasks.Count >= MaxParallelTasks) { urlTasksCount = RunningTasks.Count(v => v.Value != null && (!v.Value.Parameters.Preload && v.Value.Parameters.Source == ImageSource.Url)); preloadTasksCount = RunningTasks.Count(v => v.Value != null && v.Value.Parameters.Preload); preloadOrUrlTasksCount = preloadTasksCount + urlTasksCount; if (preloadOrUrlTasksCount == 0 || preloadOrUrlTasksCount != MaxParallelTasks) { return; } // Allow only half of MaxParallelTasks as additional allowed tasks when preloading occurs to prevent starvation if (RunningTasks.Count - Math.Max(1, Math.Min(preloadOrUrlTasksCount, MaxParallelTasks / 2)) >= MaxParallelTasks) { return; } } int numberOfTasks = MaxParallelTasks - RunningTasks.Count + Math.Min(preloadOrUrlTasksCount, MaxParallelTasks / 2); tasksToRun = new Dictionary <string, IImageLoaderTask>(); IImageLoaderTask task = null; while (tasksToRun.Count < numberOfTasks && PendingTasks.TryDequeue(out task)) { if (task == null || task.IsCancelled || task.IsCompleted) { continue; } // We don't want to load, at the same time, images that have same key or same raw key at the same time // This way we prevent concurrent downloads and benefit from caches string rawKey = task.KeyRaw; if (RunningTasks.ContainsKey(rawKey) || tasksToRun.ContainsKey(rawKey)) { SimilarTasks.Add(task); continue; } if (preloadOrUrlTasksCount != 0) { if (!task.Parameters.Preload && (urlTasksCount == 0 || task.Parameters.Source != ImageSource.Url)) { tasksToRun.Add(rawKey, task); } else { Enqueue(task); break; } } else { tasksToRun.Add(rawKey, task); } } foreach (var item in tasksToRun) { RunningTasks.Add(item.Key, item.Value); Interlocked.Increment(ref _statsTotalRunning); } } if (tasksToRun != null && tasksToRun.Count > 0) { var tasks = tasksToRun.Select(p => RunImageLoadingTaskAsync(p.Value)); await Task.WhenAll(tasks).ConfigureAwait(false); } }
void Enqueue(IImageLoaderTask task) { PendingTasks.Enqueue(task, task.Parameters.Priority ?? GetDefaultPriority(task.Parameters.Source)); }
protected async Task TakeFromPendingTasksAndRunAsync() { Dictionary<string, PendingTask> tasksToRun = null; lock (_pendingTasksLock) { var preloadOrUrlTasksCount = 0; var urlTasksCount = 0; var preloadTasksCount = 0; if (RunningTasks.Count >= MaxParallelTasks) { urlTasksCount = RunningTasks.Count( v => (v.Value?.ImageLoadingTask != null) && !v.Value.ImageLoadingTask.Parameters.Preload && (v.Value.ImageLoadingTask.Parameters.Source == ImageSource.Url)); preloadTasksCount = RunningTasks.Count(v => (v.Value?.ImageLoadingTask != null) && v.Value.ImageLoadingTask.Parameters.Preload); preloadOrUrlTasksCount = preloadTasksCount + urlTasksCount; if ((preloadOrUrlTasksCount == 0) || (preloadOrUrlTasksCount != MaxParallelTasks)) return; // Allow only half of MaxParallelTasks as additional allowed tasks when preloading occurs to prevent starvation if (RunningTasks.Count - Math.Max(1, Math.Min(preloadOrUrlTasksCount, MaxParallelTasks/2)) >= MaxParallelTasks) return; } var numberOfTasks = MaxParallelTasks - RunningTasks.Count + Math.Min(preloadOrUrlTasksCount, MaxParallelTasks/2); tasksToRun = new Dictionary<string, PendingTask>(); foreach ( var task in PendingTasks.Where(t => !t.ImageLoadingTask.IsCancelled && !t.ImageLoadingTask.IsCompleted) .OrderByDescending( t => t.ImageLoadingTask.Parameters.Priority ?? GetDefaultPriority(t.ImageLoadingTask.Parameters.Source)) .ThenBy(t => t.Position)) { // We don't want to load, at the same time, images that have same key or same raw key at the same time // This way we prevent concurrent downloads and benefit from caches var rawKey = task.ImageLoadingTask.KeyRaw; if (RunningTasks.ContainsKey(rawKey) || tasksToRun.ContainsKey(rawKey)) continue; if (preloadOrUrlTasksCount != 0) { if (!task.ImageLoadingTask.Parameters.Preload && ((urlTasksCount == 0) || (task.ImageLoadingTask.Parameters.Source != ImageSource.Url))) tasksToRun.Add(rawKey, task); } else { tasksToRun.Add(rawKey, task); } if (tasksToRun.Count == numberOfTasks) break; } } if ((tasksToRun != null) && (tasksToRun.Count > 0)) if (tasksToRun.Count == 1) { await RunImageLoadingTaskAsync(tasksToRun.Values.First()).ConfigureAwait(false); } else { var tasks = tasksToRun.Select(p => RunImageLoadingTaskAsync(p.Value)); await Task.WhenAll(tasks).ConfigureAwait(false); } }
protected void QueueImageLoadingTask(IImageLoaderTask task) { var 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 if (similarRunningTask.ImageLoadingTask != null) { if (task.Parameters.Priority.HasValue && (!similarRunningTask.ImageLoadingTask.Parameters.Priority.HasValue || (task.Parameters.Priority.Value > similarRunningTask.ImageLoadingTask.Parameters.Priority.Value))) similarRunningTask.ImageLoadingTask.Parameters.WithPriority(task.Parameters.Priority.Value); if (task.Parameters.OnDownloadProgress != null) { var similarTaskOnDownloadProgress = similarRunningTask.ImageLoadingTask.Parameters.OnDownloadProgress; similarRunningTask.ImageLoadingTask.Parameters.DownloadProgress(obj => { similarTaskOnDownloadProgress?.Invoke(obj); task.Parameters.OnDownloadProgress(obj); }); } } } if (PauseWork) return; if ((similarRunningTask == null) || !currentPendingTask.ImageLoadingTask.CanUseMemoryCache) TakeFromPendingTasksAndRun(); else WaitForSimilarTaskFinished(currentPendingTask, similarRunningTask); }
protected async Task TakeFromPendingTasksAndRunAsync() { if (PendingTasks.Count == 0) { return; } Dictionary <string, IImageLoaderTask> tasksToRun = null; var preloadOrUrlTasksCount = 0; var urlTasksCount = 0; var preloadTasksCount = 0; lock (_lock) { if (RunningTasks.Count >= MaxParallelTasks) { urlTasksCount = RunningTasks.Count(v => v.Value != null && !v.Value.Parameters.Preload && v.Value.Parameters.Source == ImageSource.Url); preloadTasksCount = RunningTasks.Count(v => v.Value != null && v.Value.Parameters.Preload); preloadOrUrlTasksCount = preloadTasksCount + urlTasksCount; if (preloadOrUrlTasksCount == 0 || preloadOrUrlTasksCount != MaxParallelTasks) { return; } // Allow only half of MaxParallelTasks as additional allowed tasks when preloading occurs to prevent starvation if (RunningTasks.Count - Math.Max(1, Math.Min(preloadOrUrlTasksCount, MaxParallelTasks / 2)) >= MaxParallelTasks) { return; } } var numberOfTasks = MaxParallelTasks - RunningTasks.Count + Math.Min(preloadOrUrlTasksCount, MaxParallelTasks / 2); tasksToRun = new Dictionary <string, IImageLoaderTask>(); IImageLoaderTask task = null; while (tasksToRun.Count < numberOfTasks && PendingTasks.TryDequeue(out task)) { if (task == null || task.IsCancelled || task.IsCompleted) { continue; } // We don't want to load, at the same time, images that have same key or same raw key at the same time // This way we prevent concurrent downloads and benefit from caches var rawKey = task.KeyRaw; if (RunningTasks.ContainsKey(rawKey) || tasksToRun.ContainsKey(rawKey)) { SimilarTasks.Add(task); continue; } if (preloadOrUrlTasksCount != 0) { if (!task.Parameters.Preload && (urlTasksCount == 0 || task.Parameters.Source != ImageSource.Url)) { tasksToRun.Add(rawKey, task); } else { Enqueue(task); break; } } else { tasksToRun.Add(rawKey, task); } } foreach (var item in tasksToRun) { RunningTasks.Add(item.Key, item.Value); Interlocked.Increment(ref _statsTotalRunning); } } if (tasksToRun != null && tasksToRun.Count > 0) { var tasks = tasksToRun.Select(async p => { await Task.Factory.StartNew(async() => { try { await RunImageLoadingTaskAsync(p.Value).ConfigureAwait(false); } catch (Exception ex) { Logger.Error("TakeFromPendingTasksAndRun exception", ex); } }, CancellationToken.None, TaskCreationOptions.PreferFairness | TaskCreationOptions.DenyChildAttach | TaskCreationOptions.HideScheduler, TaskScheduler.Default).ConfigureAwait(false); }); await Task.WhenAll(tasks).ConfigureAwait(false); } }
private void Enqueue(IImageLoaderTask task) { int priority = task.Priority ?? task.ImageSource.Source.DefaultLoadingPriority; PendingTasks.Enqueue(task, priority); }