Image depuis HTTP avec C# XAML – Comparatifs et Performances – Partie 1


Introduction

Chargement Bitmap Image en Http

Voici un article en 2 parties pour décrire les différentes implémentations possibles de la lecture d’images provenant d’un serveur en Http.
En terme de performances, il existe des différences assez conséquentes suivant les implémentations choisies.

Nous allons voir que parfois les résultats sont assez surprenants.

Charger une image depuis XAML

Le moyen le plus simple pour charger une image reste l’implémentation XAML.

ImageUrl est de type Url et peut être déclarée de cette façon dans le viewModel associé à la Page.

Cette implémentation est très efficace, le contrôle XAML gère quasiment tout pour vous :

  • le chargement en asynchrone : Ne fige pas l’affichage de l’interface lors du chargement
  • la mise en cache mémoire (un seul chargement)
  • L’optimisation http (évite un échange serveur si l’image est déjà chargée)

Cependant l’image chargée en XAML sera de nouveau rechargée à chaque lancement de l’application.
Afin de mettre en place un système de cache persisté, il est nécessaire de charger le contenu de l’image et de la sauvegarder sur le téléphone dans l’Isolated Storage.

Quelles sont les méthodes possibles pour charger et afficher une image en asynchrone ?

Voici 9 façons de faire en Universal Apps (Windows Phone XAML ou Windows 8.1). Leurs temps de réponse seront mesurés sur Windows Phone 8.1 et exposés dans la 2ème partie de cet article.

Implémentations

 

1 – DataWriter

La première implémentation, la plus classique, est d’utiliser un httpClient pour récupérer le flux sous forme de Stream puis de le transférer dans le BitmapImage en passant par un DataWritter.

Windows 8 et les Universal Apps nous obligent à passer par un nouveau type de Stream le InMemoryRandomAccessStream pour l’afficher comme source dans le BitmapImage.

Rien d’exceptionnel, c’est l’exemple le plus courant que l’on trouve sur les implémentations Windows 8.0.

2 – AsRandomAccessStream

La version 8.1 de Windows et Windows Phone Xaml a introduit une conversion implicite du MemoryStream en IMemoryRandomAccessStream.
Le même code peut être écrite de cette façon maintenant :

Le code est du coup plus léger et plus lisible. Est-il plus rapide ?

3 – AsRandomAccessStream and ConfigureAwait.

Afin d’améliorer le concept la troisème écriture va utiliser l’option ConfigureAwait(false) sur les méthodes async/await.
Le ConfigureAwait(false) empêche au thread qui exécute la méthode en asynchrone de retourner sur le thread initial (souvent le Thread UI).

Lorsqu’il y a plusieurs await à la suite qui ne nécessitent pas un affichage, cela peut accélérer considérablement les performances.
Par contre BitmapImage a besoin de s’exécuter dans le ThreadUI, il faudra donc indiquer le retour au Thread UI avec la méthode RunAsync du Dispatcher.
Pour exécuter une action depuis une classe il faudra utiliser la syntaxe suivante pour retrouver le Dispatcher associé à l’écran principal.

Ce qui nous donne :

 4 – Transformation du flux MemoryStream dans un Task à part

La solution suivante consiste à réécrire la transformation du MemoryStream vers IRandomAccessTream dans une tâche exécutée en asynchrone.
La procédure de conversion ressemble à ça.

Maintenant nous pouvons utiliser cette méthode dans le chargement de l’image :

5 – Remplacement du HttpClient par le HttpWebRequest

On remplace l’accès http qui se fait simplement par le HttpClient par un HttpWebRequest.
Le HttpWebRequest est moins évolué que le HttpClient et permet un paramétrage plus fin tout en étant plus performant.
Rien de compliqué, le code reste identique, seul le début change.

6 – Actions à la place du Async / Await

Cela reste toujours une énigme mais l’utilisation du mode standard sans le async/await reste la plus performante (cf. article sur Windows Phone 7 et 8).
Le code est réécrit dans un fonctionnement avec des types Action (Comme au bon vieux temps)

La seule différence avec la méthode 5 est donc le résultat qui est retourné par une Action.
Afin de l’utiliser facilement, la fonction est appelée dans un mécanisme async/await de cette façon :

7 – HttpWebRequest et AsRandomAccessStream

Une variante de la 3ème méthode avec le HttpWebRequest

 8 – HttpWebRequest et AsRandomAccessStream avec Action

C’est une variante de la solution 6. On remplace la conversion maison par le AsRandomAccessStream. Le tout est retourné par une Action.

9 – HttpWebRequest, AsRandom Access Stream sans ConfigureAwait

Le même scénario que le 2 mais en utilisant HttpWebRequest à la place de HttpClient.

 Conclusion de la Partie 1

Plusieurs implémentations et des différences dans les résultats de performances. Certes pas énormes : 15-20%% d’écart, mais tout de même 15% de performances sur des devices mobiles c’est toujours bon à prendre.

Quelle est la méthode la plus rapide selon vous ?

Réponse très prochainement dans la deuxième Partie.

Laissez un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

6 − 5 =