Beispiel #1
0
        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.");
            }
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        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);
            }
        }
Beispiel #4
0
        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.");
            }
        }
Beispiel #5
0
        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;
             }
         }
     }
 }
Beispiel #7
0
 public virtual void RemovePendingTask(IImageLoaderTask task)
 {
     lock (_pendingTasksLock)
     {
         PendingTasks.RemoveAll(p => p.ImageLoadingTask == task);
     }
 }
Beispiel #8
0
 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();
     }
 }
Beispiel #9
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);
            }
        }
Beispiel #10
0
        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);
            }
        }
Beispiel #11
0
 public virtual void RemovePendingTask(IImageLoaderTask task)
 {
     if (task != null)
     {
         lock (_lock)
         {
             PendingTasks.TryRemove(task);
             SimilarTasks.Remove(task);
         }
     }
 }
Beispiel #12
0
        public virtual void Cancel(Func <IImageLoaderTask, bool> predicate)
        {
            lock (_lock)
            {
                foreach (var task in PendingTasks.Where(p => predicate(p)))
                {
                    task?.Cancel();
                }

                SimilarTasks.RemoveAll(predicate);
            }
        }
Beispiel #13
0
        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();
 }
Beispiel #15
0
        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);
                }
            }
        }
Beispiel #16
0
        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);
                }
            }
        }
Beispiel #17
0
        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);
                }
            }
        }
Beispiel #18
0
 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);
     }
 }
Beispiel #19
0
        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();
            }
        }
Beispiel #20
0
 /// <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();
            }
        }
Beispiel #22
0
        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);
                }
            });
        }
Beispiel #23
0
        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);
            }
        }
Beispiel #24
0
 void Enqueue(IImageLoaderTask task)
 {
     PendingTasks.Enqueue(task, task.Parameters.Priority ?? GetDefaultPriority(task.Parameters.Source));
 }
Beispiel #25
0
        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);
                }
        }
Beispiel #26
0
        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);
            }
        }
Beispiel #28
0
        private void Enqueue(IImageLoaderTask task)
        {
            int priority = task.Priority ?? task.ImageSource.Source.DefaultLoadingPriority;

            PendingTasks.Enqueue(task, priority);
        }