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 || ExitTasksEarly) { 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 { QueueImageLoadingTask(task); } catch (Exception ex) { Logger.Error(string.Format("Image loaded failed: {0}", task?.Key), ex); } }); }
/// <summary> /// Schedules the image loading. If image is found in cache then it returns it, otherwise it loads it. /// </summary> /// <param name="task">Image loading task.</param> public void LoadImage(IImageLoaderTask task) { if (task == null) { return; } #pragma warning disable 4014 Task.Run(async() => { if (task.Parameters.DelayInMs != null && task.Parameters.DelayInMs > 0) { await Task.Delay(task.Parameters.DelayInMs.Value).ConfigureAwait(false); } if (task.IsCancelled) { task.Parameters.Dispose(); // this will ensure we don't keep a reference due to callbacks return; } if (!task.Parameters.Preload) { List <PendingTask> pendingTasksCopy; lock (_pendingTasksLock) { pendingTasksCopy = _pendingTasks.ToList(); } foreach (var pendingTask in pendingTasksCopy) { if (pendingTask.ImageLoadingTask != null && pendingTask.ImageLoadingTask.UsesSameNativeControl(task)) { pendingTask.ImageLoadingTask.CancelIfNeeded(); } } } bool loadedFromCache = await task.PrepareAndTryLoadingFromCacheAsync().ConfigureAwait(false); if (loadedFromCache) { if (task.Parameters.OnFinish != null) { task.Parameters.OnFinish(task); } task.Dispose(); return; // image successfully loaded from cache } if (task.IsCancelled || _pauseWork) { task.Parameters.Dispose(); // this will ensure we don't keep a reference due to callbacks return; } QueueAndGenerateImage(task); }); #pragma warning restore 4014 }
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); } }
/// <summary> /// Schedules the image loading. If image is found in cache then it returns it, otherwise it loads it. /// </summary> /// <param name="task">Image loading task.</param> public async void LoadImage(IImageLoaderTask task) { if (task == null) { return; } if (task.IsCancelled) { task.Parameters.Dispose(); // this will ensure we don't keep a reference due to callbacks return; } List <PendingTask> pendingTasksCopy; lock (_pendingTasksLock) { pendingTasksCopy = _pendingTasks.ToList(); } foreach (var pendingTask in pendingTasksCopy) { if (pendingTask.ImageLoadingTask != null && pendingTask.ImageLoadingTask.UsesSameNativeControl(task)) { pendingTask.ImageLoadingTask.CancelIfNeeded(); } } bool loadedFromCache = false; if (task.CanUseMemoryCache()) { loadedFromCache = await task.PrepareAndTryLoadingFromCacheAsync().ConfigureAwait(false); } if (loadedFromCache) { if (task.Parameters.OnFinish != null) { task.Parameters.OnFinish(task); } task.Dispose(); return; // image successfully loaded from cache } if (task.IsCancelled || _pauseWork) { task.Parameters.Dispose(); // this will ensure we don't keep a reference due to callbacks return; } QueueAndGenerateImage(task); }
protected async Task RunImageLoadingTaskAsync(IImageLoaderTask pendingTask) { var keyRaw = pendingTask.KeyRaw; try { if (Configuration.VerbosePerformanceLogging) { LogSchedulerStats(); Stopwatch stopwatch = Stopwatch.StartNew(); await pendingTask.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, pendingTask.Key)); } else { await pendingTask.RunAsync().ConfigureAwait(false); } } finally { lock (_runningTasksLock) { RunningTasks.Remove(keyRaw); lock (_similarTasksLock) { if (SimilarTasks.Count > 0) { SimilarTasks.RemoveAll(v => v == null || v.IsCompleted || v.IsCancelled); var similarItems = SimilarTasks.Where(v => v.KeyRaw == keyRaw).ToList(); foreach (var similar in similarItems) { SimilarTasks.Remove(similar); LoadImage(similar); } } } } pendingTask?.Dispose(); await TakeFromPendingTasksAndRunAsync().ConfigureAwait(false); } }
public virtual void Cancel(IImageLoaderTask task) { try { if ((task != null) && !task.IsCancelled && !task.IsCompleted) task.Cancel(); } catch (Exception e) { Logger.Error(string.Format("Cancelling task failed: {0}", task?.Key), e); } finally { task?.Dispose(); EvictStaleTasks(); } }
private async Task LoadImageAsync(IImageLoaderTask task) { if (task.IsCancelled) { task.Parameters?.Dispose(); // this will ensure we don't keep a reference due to callbacks 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(); } } } } bool loadedFromCache = await task.PrepareAndTryLoadingFromCacheAsync().ConfigureAwait(false); if (loadedFromCache) { if (task.Parameters.OnFinish != null) { task.Parameters.OnFinish(task); } task.Dispose(); return; // image successfully loaded from cache } if (task.IsCancelled || _pauseWork) { task.Parameters?.Dispose(); // this will ensure we don't keep a reference due to callbacks return; } QueueAndGenerateImage(task); }
private async Task LoadImageAsync(IImageLoaderTask task) { if (task.IsCancelled) { task.Parameters.Dispose(); // this will ensure we don't keep a reference due to callbacks return; } if (!task.Parameters.Preload) { foreach (var pendingTask in _pendingTasks) { if (pendingTask.Value.ImageLoadingTask != null && pendingTask.Value.ImageLoadingTask.UsesSameNativeControl(task)) { pendingTask.Value.ImageLoadingTask.CancelIfNeeded(); } } } bool loadedFromCache = await task.PrepareAndTryLoadingFromCacheAsync().ConfigureAwait(false); if (loadedFromCache) { if (task.Parameters.OnFinish != null) { task.Parameters.OnFinish(task); } task.Dispose(); return; // image successfully loaded from cache } if (task.IsCancelled || _pauseWork) { task.Parameters.Dispose(); // this will ensure we don't keep a reference due to callbacks return; } QueueAndGenerateImage(task); return; }
/// <summary> /// Schedules the image loading. If image is found in cache then it returns it, otherwise it loads it. /// </summary> /// <param name="task">Image loading task.</param> public async void LoadImage(IImageLoaderTask task) { if (task == null) return; if (task.IsCancelled) { task.Parameters.Dispose(); // this will ensure we don't keep a reference due to callbacks return; } List<PendingTask> pendingTasksCopy; lock (_pendingTasksLock) { pendingTasksCopy = _pendingTasks.ToList(); } foreach (var pendingTask in pendingTasksCopy) { if (pendingTask.ImageLoadingTask != null && pendingTask.ImageLoadingTask.UsesSameNativeControl(task)) pendingTask.ImageLoadingTask.CancelIfNeeded(); } bool loadedFromCache = false; if (task.CanUseMemoryCache()) { loadedFromCache = await task.PrepareAndTryLoadingFromCacheAsync().ConfigureAwait(false); } if (loadedFromCache) { if (task.Parameters.OnFinish != null) task.Parameters.OnFinish(task); task.Dispose(); return; // image successfully loaded from cache } if (task.IsCancelled || _pauseWork) { task.Parameters.Dispose(); // this will ensure we don't keep a reference due to callbacks return; } QueueAndGenerateImage(task); }
protected void QueueImageLoadingTask(IImageLoaderTask task) { if (task.IsCancelled || task.IsCompleted || ExitTasksEarly) { if (!task.IsCompleted) { task?.Dispose(); } return; } IImageLoaderTask similarRunningTask = null; if (!task.Parameters.Preload) { PendingTasks.CancelWhenUsesSameNativeControl(task); } 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.UpdatePriority(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); } }
/// <summary> /// Schedules the image loading. If image is found in cache then it returns it, otherwise it loads it. /// </summary> /// <param name="task">Image loading task.</param> public async void LoadImage(IImageLoaderTask task) { Interlocked.Increment(ref _loadCount); if (_verbosePerformanceLogging && (_loadCount % 10) == 0) { LogSchedulerStats(); } if (task == null) { return; } if (task.IsCancelled) { task.Parameters?.Dispose(); // this will ensure we don't keep a reference due to callbacks 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()) { var cacheResult = await task.TryLoadingFromCacheAsync().ConfigureAwait(false); if (cacheResult == CacheResult.Found) // If image is loaded from cache there is nothing to do here anymore { Interlocked.Increment(ref _statsTotalMemoryCacheHits); } if (cacheResult == CacheResult.Found || cacheResult == CacheResult.ErrorOccured) // if something weird happened with the cache... error callback has already been called, let's just leave { if (task.Parameters.OnFinish != null) { task.Parameters.OnFinish(task); } task.Dispose(); return; } } else if (task?.Parameters?.Source != ImageSource.Stream && string.IsNullOrWhiteSpace(task?.Parameters?.Path)) { _logger.Debug("ImageService: null path ignored"); return; } _dispatch = _dispatch.ContinueWith(async t => { try { await LoadImageAsync(task).ConfigureAwait(false); } catch (Exception ex) { _logger.Error("An error occured while loading image", ex); } }); }
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); }
private async Task LoadImageAsync(IImageLoaderTask task) { if (task.IsCancelled) { task.Parameters?.Dispose(); // this will ensure we don't keep a reference due to callbacks 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(); } } } bool loadedFromCache = await task.PrepareAndTryLoadingFromCacheAsync().ConfigureAwait(false); if (loadedFromCache) { if (task.Parameters.OnFinish != null) task.Parameters.OnFinish(task); task.Dispose(); return; // image successfully loaded from cache } if (task.IsCancelled || _pauseWork) { task.Parameters?.Dispose(); // this will ensure we don't keep a reference due to callbacks return; } QueueAndGenerateImage(task); }
/// <summary> /// Schedules the image loading. If image is found in cache then it returns it, otherwise it loads it. /// </summary> /// <param name="task">Image loading task.</param> public async void LoadImage(IImageLoaderTask task) { Interlocked.Increment(ref _loadCount); if (_verbosePerformanceLogging && (_loadCount % 10) == 0) { LogSchedulerStats(); } if (task == null) return; if (task.IsCancelled) { task.Parameters?.Dispose(); // this will ensure we don't keep a reference due to callbacks 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()) { var cacheResult = await task.TryLoadingFromCacheAsync().ConfigureAwait(false); if (cacheResult == CacheResult.Found) // If image is loaded from cache there is nothing to do here anymore { Interlocked.Increment(ref _statsTotalMemoryCacheHits); } if (cacheResult == CacheResult.Found || cacheResult == CacheResult.ErrorOccured) // if something weird happened with the cache... error callback has already been called, let's just leave { if (task.Parameters.OnFinish != null) task.Parameters.OnFinish(task); task.Dispose(); return; } } else if (task?.Parameters?.Source != ImageSource.Stream && string.IsNullOrWhiteSpace(task?.Parameters?.Path)) { _logger.Debug("ImageService: null path ignored"); return; } _dispatch = _dispatch.ContinueWith(async t => { try { await LoadImageAsync(task).ConfigureAwait(false); } catch (Exception ex) { _logger.Error("An error occured while loading image", ex); } }); }
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); } }); }