private void WaitForAvailableThread() { System.DateTime dtStart = System.DateTime.Now; while (!disposing && MaximumConcurrency <= RunningTasks.Count()) { System.Threading.Thread.Sleep(10); if (System.DateTime.Now - dtStart >= TimeOut) { throw new System.TimeoutException( string.Format(IO.FileParser.Properties.Resources.ResourceManager.GetString("ThreadNotAvailable"), TimeOut.ToString("HH:mm:ss.fff"))); } } }
/// <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); } } }
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); } }
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); } }
public override async Task ExecuteAsync(object parameter) { _shell.StatusText = $"Open Async task {Thread.CurrentThread.ManagedThreadId } of {RunningTasks.Count()} "; await Task.Delay(2000); _shell.StatusText = $"Completed Open Async task {Thread.CurrentThread.ManagedThreadId } of {RunningTasks.Count()} "; }
protected async Task TakeFromPendingTasksAndRunAsync() { if (PendingTasks.Count == 0) { return; } Dictionary <string, IImageLoaderTask>?tasksToRun = null; int urlTasksCount = 0; lock (_lock) { if (RunningTasks.Count >= MaxParallelTasks) { urlTasksCount = RunningTasks.Count(v => v.Value != null && v.Value.ImageSource.Source is UriSource); if (urlTasksCount == 0 || urlTasksCount != 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(urlTasksCount, MaxParallelTasks / 2)) >= MaxParallelTasks) { return; } } int numberOfTasks = MaxParallelTasks - RunningTasks.Count + Math.Min(urlTasksCount, MaxParallelTasks / 2); tasksToRun = new Dictionary <string, IImageLoaderTask>(); while (tasksToRun.Count < numberOfTasks && PendingTasks.TryDequeue(out IImageLoaderTask? 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 (urlTasksCount != 0) { if (!(task.ImageSource.Source is UriSource)) { 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) { _imageLoader.Logger?.Error("TakeFromPendingTasksAndRun exception", ex); } }, CancellationToken.None, TaskCreationOptions.PreferFairness | TaskCreationOptions.DenyChildAttach | TaskCreationOptions.HideScheduler, TaskScheduler.Default).ConfigureAwait(false); }); await Task.WhenAll(tasks).ConfigureAwait(false); } }