Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Cree aplicaciones winUI con Windows App SDK que accedan al sistema de archivos de forma eficaz, evitando problemas de rendimiento causados por la latencia de disco y el uso innecesario de memoria o CPU.
Si desea acceder a una gran colección de archivos y desea tener acceso a valores de propiedad distintos de las propiedades Name, FileType y Path típicas, puede acceder a ellos mediante la creación de QueryOptions y la llamada a SetPropertyPrefetch. El método SetPropertyPrefetch puede mejorar drásticamente el rendimiento de las aplicaciones que muestran una colección de elementos obtenidos del sistema de archivos, como una colección de imágenes. En el siguiente conjunto de ejemplos se muestran algunas maneras de acceder a varios archivos.
En el primer ejemplo se usa Windows.Storage.StorageFolder.GetFilesAsync para recuperar la información de nombre de un conjunto de archivos. Este enfoque ofrece un buen rendimiento porque el ejemplo únicamente accede a la propiedad "nombre".
StorageFolder library = Windows.Storage.KnownFolders.PicturesLibrary;
IReadOnlyList<StorageFile> files = await library.GetFilesAsync(Windows.Storage.Search.CommonFileQuery.OrderByDate);
for (int i = 0; i < files.Count; i++)
{
// Do something with the name of each file.
string fileName = files[i].Name;
}
En el segundo ejemplo se usa Windows.Storage.StorageFolder.GetFilesAsync y, a continuación, se recuperan las propiedades de imagen de cada archivo. Este enfoque proporciona un rendimiento deficiente.
StorageFolder library = Windows.Storage.KnownFolders.PicturesLibrary;
IReadOnlyList<StorageFile> files = await library.GetFilesAsync(Windows.Storage.Search.CommonFileQuery.OrderByDate);
for (int i = 0; i < files.Count; i++)
{
ImageProperties imgProps = await files[i].Properties.GetImagePropertiesAsync();
// Do something with the date the image was taken.
DateTimeOffset date = imgProps.DateTaken;
}
En el tercer ejemplo se usa QueryOptions para obtener información sobre un conjunto de archivos. Este enfoque proporciona un rendimiento mucho mejor que el ejemplo anterior.
// Set QueryOptions to prefetch our specific properties.
var queryOptions = new Windows.Storage.Search.QueryOptions(CommonFileQuery.OrderByDate, null);
queryOptions.SetThumbnailPrefetch(
ThumbnailMode.PicturesView,
100,
ThumbnailOptions.ReturnOnlyIfCached);
queryOptions.SetPropertyPrefetch(
PropertyPrefetchOptions.ImageProperties,
new string[] { "System.Size" });
StorageFileQueryResult queryResults = KnownFolders.PicturesLibrary.CreateFileQueryWithOptions(queryOptions);
IReadOnlyList<StorageFile> files = await queryResults.GetFilesAsync();
foreach (var file in files)
{
ImageProperties imageProperties = await file.Properties.GetImagePropertiesAsync();
// Do something with the date the image was taken.
DateTimeOffset dateTaken = imageProperties.DateTaken;
// Performance gains increase with the number of properties that are accessed.
IDictionary<string, object> propertyResults =
await file.Properties.RetrievePropertiesAsync(new string[] { "System.Size" });
// Get or set extra properties here.
var systemSize = propertyResults["System.Size"];
}
Si va a realizar varias operaciones en objetos Windows.Storage como Windows.Storage.ApplicationData.Current.LocalFolder, cree una variable local para hacer referencia a ese origen de almacenamiento para que no vuelva a crear objetos intermedios cada vez que acceda a él.
Rendimiento de stream en C#
Buffering entre flujos de Windows Runtime y .NET
Hay muchos escenarios en los que es posible que quiera convertir una secuencia de Windows Runtime (como Windows.Storage.Streams.IInputStream o IOutputStream) a una secuencia de .NET (System.IO.Stream). Por ejemplo, esto resulta útil cuando se escribe una aplicación winUI y se quiere usar código .NET existente que funciona en secuencias con las API de Almacenamiento de Windows. Para habilitar esto, .NET proporciona métodos de extensión que permiten convertir entre tipos de flujo de .NET y Windows Runtime. Para obtener más información, consulta WindowsRuntimeStreamExtensions.
Al convertir una secuencia de Windows Runtime en una secuencia de .NET, se crea eficazmente un adaptador para la secuencia subyacente de Windows Runtime. En algunas circunstancias, hay un costo en tiempo de ejecución asociado a invocar métodos en secuencias de Windows Runtime. Esto puede afectar a la velocidad de la aplicación, especialmente en escenarios en los que se realizan muchas operaciones pequeñas, frecuentes de lectura o escritura.
Para ayudar a acelerar las aplicaciones, los adaptadores de flujo de Windows Runtime contienen un búfer de datos. En el ejemplo de código siguiente se muestran pequeñas lecturas consecutivas mediante un adaptador de flujo de Windows Runtime con un tamaño de búfer predeterminado.
StorageFile file = await Windows.Storage.ApplicationData.Current
.LocalFolder.GetFileAsync("example.txt");
Windows.Storage.Streams.IInputStream windowsRuntimeStream =
await file.OpenReadAsync();
byte[] destinationArray = new byte[8];
// Create an adapter with the default buffer size.
using (var managedStream = windowsRuntimeStream.AsStreamForRead())
{
// Read 8 bytes into destinationArray.
// A larger block is actually read from the underlying
// windowsRuntimeStream and buffered within the adapter.
await managedStream.ReadAsync(destinationArray, 0, 8);
// Read 8 more bytes into destinationArray.
// This call may complete much faster than the first call
// because the data is buffered and no call to the
// underlying windowsRuntimeStream needs to be made.
await managedStream.ReadAsync(destinationArray, 0, 8);
}
Este comportamiento de almacenamiento en búfer predeterminado es deseable en la mayoría de los escenarios en los que se convierte una secuencia de Windows Runtime en una secuencia de .NET. Sin embargo, en algunos escenarios puede que desee ajustar el comportamiento del buffer para aumentar el rendimiento.
Trabajar con grandes conjuntos de datos
Al leer o escribir conjuntos de datos más grandes, puede aumentar el rendimiento de lectura o escritura proporcionando un tamaño de búfer grande a los métodos de extensión AsStreamForRead, AsStreamForWrite y AsStream . Esto proporciona al adaptador de flujo un tamaño de búfer interno mayor. Por ejemplo, al pasar una secuencia que procede de un archivo grande a un analizador XML, el analizador puede hacer muchas lecturas pequeñas secuenciales de la secuencia. Un búfer grande puede reducir el número de llamadas a la secuencia subyacente de Windows Runtime y aumentar el rendimiento.
Nota:
Tenga cuidado al establecer un tamaño de búfer mayor que aproximadamente 80 KB, ya que esto puede provocar fragmentación en el heap del recolector de basura. Para obtener instrucciones relacionadas, consulte Mejora del rendimiento de la recolección de elementos no utilizados en aplicaciones WinUI. En el ejemplo de código siguiente se crea un adaptador de flujo administrado con un búfer de 81 920 bytes.
// Create a stream adapter with an 80 KB buffer.
Stream managedStream = nativeStream.AsStreamForRead(bufferSize: 81920);
Los métodos Stream.CopyTo y CopyToAsync también asignan un búfer local para copiar entre secuencias. Al igual que con el método de extensión AsStreamForRead , es posible que pueda obtener un mejor rendimiento para las copias de secuencias grandes invalidando el tamaño de búfer predeterminado. En el ejemplo de código siguiente se muestra cómo cambiar el tamaño predeterminado del búfer de una llamada CopyToAsync .
MemoryStream destination = new MemoryStream();
// Copies the buffer into memory using the default copy buffer.
await managedStream.CopyToAsync(destination);
// Copy the buffer into memory using a 1 MB copy buffer.
await managedStream.CopyToAsync(destination, bufferSize: 1024 * 1024);
En este ejemplo se usa un tamaño de búfer de 1 MB, que es mayor que los 80 KB recomendados anteriormente. El uso de un búfer de gran tamaño puede mejorar el rendimiento de la operación de copia para conjuntos de datos muy grandes (es decir, varios cientos de megabytes). Sin embargo, este búfer se asigna en el montón de objetos grandes y podría degradar el rendimiento de la recolección de basura. Solo debes usar tamaños de búfer grandes si mejoran notablemente el rendimiento de la aplicación.
Cuando trabajas con un gran número de secuencias simultáneamente, puedes querer reducir o eliminar la sobrecarga de memoria de la memoria intermedia. Puede especificar un búfer más pequeño o establecer el parámetro bufferSize en 0 para desactivar el almacenamiento en búfer completamente para ese adaptador de flujo. Todavía puede lograr un buen rendimiento de transferencia sin almacenar en búfer si realiza lecturas y escrituras de gran tamaño en la secuencia administrada.
Realización de operaciones sensibles a la latencia
También puedes evitar el almacenamiento en búfer si quieres lecturas y escrituras de baja latencia y no quieres leer en bloques grandes fuera de la secuencia subyacente de Windows Runtime. Por ejemplo, es posible que necesite lecturas y escrituras de baja latencia si utiliza el flujo para las comunicaciones de red.
En una aplicación de chat, puede usar un flujo a través de una interfaz de red para enviar mensajes de ida y vuelta. En este caso, quiere enviar mensajes tan pronto como estén listos y no esperar a que el búfer se llene. Si estableces el tamaño del búfer en 0 al llamar a los métodos de extensión AsStreamForRead, AsStreamForWrite y AsStream , el adaptador resultante no asignará un búfer y todas las llamadas manipularán directamente la secuencia subyacente de Windows Runtime.