Update TileImageLoader.cs

This commit is contained in:
ClemensFischer 2025-08-21 08:23:55 +02:00
parent 05824e603b
commit 2dc954341e

View file

@ -3,6 +3,7 @@ using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -10,6 +11,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
#if WPF #if WPF
using System.Windows.Media; using System.Windows.Media;
using static System.Net.WebRequestMethods;
#elif UWP #elif UWP
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;
#elif WINUI #elif WINUI
@ -82,35 +84,26 @@ namespace MapControl
/// </summary> /// </summary>
public async Task LoadTilesAsync(IEnumerable<Tile> tiles, TileSource tileSource, string cacheName, IProgress<double> progress, CancellationToken cancellationToken) public async Task LoadTilesAsync(IEnumerable<Tile> tiles, TileSource tileSource, string cacheName, IProgress<double> progress, CancellationToken cancellationToken)
{ {
var pendingTiles = tiles.Where(tile => tile.IsPending).ToList(); var pendingTiles = new ConcurrentStack<Tile>(tiles.Where(tile => tile.IsPending).Reverse());
var tileCount = pendingTiles.Count;
var taskCount = Math.Min(tileCount, MaxLoadTasks);
if (pendingTiles.Count > 0) if (taskCount > 0)
{ {
var progressCount = 0;
if (Cache == null || tileSource.UriTemplate == null || !tileSource.UriTemplate.StartsWith("http")) if (Cache == null || tileSource.UriTemplate == null || !tileSource.UriTemplate.StartsWith("http"))
{ {
cacheName = null; // disable tile image caching cacheName = null; // disable caching
} }
using (var semaphore = new SemaphoreSlim(MaxLoadTasks, MaxLoadTasks)) async Task LoadTilesFromQueue()
{ {
async Task LoadTile(Tile tile) while (!cancellationToken.IsCancellationRequested && pendingTiles.TryPop(out var tile))
{ {
try
{
await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
return;
}
tile.IsPending = false; tile.IsPending = false;
progress?.Report((double)++progressCount / pendingTiles.Count); progress?.Report((double)(tileCount - pendingTiles.Count) / tileCount);
Logger?.LogTrace("[{thread}] Loading tile image {zoom}/{column}/{row}", Environment.CurrentManagedThreadId, tile.ZoomLevel, tile.Column, tile.Row); Logger?.LogTrace("[{thread}] Load {zoom}/{column}/{row}", Environment.CurrentManagedThreadId, tile.ZoomLevel, tile.Column, tile.Row);
try try
{ {
@ -120,18 +113,30 @@ namespace MapControl
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger?.LogError(ex, "Failed loading tile image {zoom}/{column}/{row}", tile.ZoomLevel, tile.Column, tile.Row); Logger?.LogError(ex, "Failed loading {zoom}/{column}/{row}", tile.ZoomLevel, tile.Column, tile.Row);
}
}
} }
semaphore.Release(); try
{
var tasks = new Task[taskCount];
for (int i = 0; i < taskCount; i++)
{
tasks[i] = Task.Run(LoadTilesFromQueue, cancellationToken);
} }
await Task.WhenAll(pendingTiles.Select(tile => Task.Run(async () => await LoadTile(tile)))); await Task.WhenAll(tasks);
}
catch (OperationCanceledException)
{
// no action
} }
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
Logger?.LogTrace("Cancelled LoadTilesAsync with {count} pending tiles", pendingTiles.Count); Logger?.LogTrace("Cancelled LoadTilesAsync with {count} queued tiles", pendingTiles.Count);
} }
} }
} }