Optimera filåtkomst

Skapa UWP-appar (Universal Windows Platform) som kommer åt filsystemet effektivt, vilket undviker prestandaproblem på grund av diskfördröjning och minnes-/CPU-cykler.

När du vill komma åt en stor samling filer och du vill komma åt andra egenskapsvärden än de typiska egenskaperna Namn, FileType och Sökväg kan du komma åt dem genom att skapa QueryOptions och anropa SetPropertyPrefetch. Metoden SetPropertyPrefetch kan avsevärt förbättra prestandan för appar som visar en samling objekt som hämtats från filsystemet, till exempel en samling bilder. Nästa uppsättning exempel visar några sätt att komma åt flera filer.

I det första exemplet används Windows.Storage.StorageFolder.GetFilesAsync för att hämta namninformationen för en uppsättning filer. Den här metoden ger bra prestanda eftersom exemplet endast använder namnegenskapen.

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;
}
Dim library As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary
Dim files As IReadOnlyList(Of StorageFile) =
    Await library.GetFilesAsync(Windows.Storage.Search.CommonFileQuery.OrderByDate)

For i As Integer = 0 To files.Count - 1
    ' do something with the name of each file
    Dim fileName As String = files(i).Name
Next i

Det andra exemplet använder Windows.Storage.StorageFolder.GetFilesAsync och hämtar sedan avbildningsegenskaperna för varje fil. Den här metoden ger dåliga prestanda.

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;
}
Dim library As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary
Dim files As IReadOnlyList(Of StorageFile) = Await library.GetFilesAsync(Windows.Storage.Search.CommonFileQuery.OrderByDate)
For i As Integer = 0 To files.Count - 1
    Dim imgProps As ImageProperties =
        Await files(i).Properties.GetImagePropertiesAsync()

    ' do something with the date the image was taken
    Dim dateTaken As DateTimeOffset = imgProps.DateTaken
Next i

I det tredje exemplet används QueryOptions för att hämta information om en uppsättning filer. Den här metoden ger mycket bättre prestanda än i föregående exempel.

// 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/Set extra properties here
    var systemSize = propertyResults["System.Size"];
}
' Set QueryOptions to prefetch our specific properties
Dim queryOptions = New Windows.Storage.Search.QueryOptions(CommonFileQuery.OrderByDate, Nothing)
queryOptions.SetThumbnailPrefetch(ThumbnailMode.PicturesView,
            100, Windows.Storage.FileProperties.ThumbnailOptions.ReturnOnlyIfCached)
queryOptions.SetPropertyPrefetch(PropertyPrefetchOptions.ImageProperties,
                                 New String() {"System.Size"})

Dim queryResults As StorageFileQueryResult = KnownFolders.PicturesLibrary.CreateFileQueryWithOptions(queryOptions)
Dim files As IReadOnlyList(Of StorageFile) = Await queryResults.GetFilesAsync()


For Each file In files
    Dim imageProperties As ImageProperties = Await file.Properties.GetImagePropertiesAsync()

    ' Do something with the date the image was taken.
    Dim dateTaken As DateTimeOffset = imageProperties.DateTaken

    ' Performance gains increase with the number of properties that are accessed.
    Dim propertyResults As IDictionary(Of String, Object) =
        Await file.Properties.RetrievePropertiesAsync(New String() {"System.Size"})

    ' Get/Set extra properties here
    Dim systemSize = propertyResults("System.Size")

Next file

Om du utför flera åtgärder på Windows.Storage-objekt som Windows.Storage.ApplicationData.Current.LocalFolderskapar du en lokal variabel som refererar till lagringskällan så att du inte återskapar mellanliggande objekt varje gång du kommer åt den.

Strömma prestanda i C# och Visual Basic

Buffring mellan UWP- och .NET-strömmar

Det finns många scenarier när du kanske vill konvertera en UWP-ström (till exempel en Windows.Storage.Streams.IInputStream eller IOutputStream) till en .NET-ström (System.IO.Stream). Detta är till exempel användbart när du skriver en UWP-app och vill använda befintlig .NET-kod som fungerar på strömmar med UWP-filsystemet. För att aktivera detta tillhandahåller .NET-API:er för UWP-appar tilläggsmetoder som gör att du kan konvertera mellan .NET- och UWP-strömtyper. Mer information finns i WindowsRuntimeStreamExtensions.

När du konverterar en UWP-ström till en .NET-ström skapar du effektivt en adapter för den underliggande UWP-strömmen. Under vissa omständigheter finns det en exekveringskostnad kopplad till att anropa metoder på UWP-strömmar. Detta kan påverka appens hastighet, särskilt i scenarier där du utför många små, frekventa läs- eller skrivåtgärder.

För att påskynda appar innehåller UWP-strömkorten en databuffert. Följande kodexempel visar små på varandra följande läsningar med hjälp av ett UWP-strömkort med en standardbuffertstorlek.

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);
}
Dim file As StorageFile = Await Windows.Storage.ApplicationData.Current -
.LocalFolder.GetFileAsync("example.txt")
Dim windowsRuntimeStream As Windows.Storage.Streams.IInputStream =
    Await file.OpenReadAsync()

Dim destinationArray() As Byte = New Byte(8) {}

' Create an adapter with the default buffer size.
Dim managedStream As Stream = windowsRuntimeStream.AsStreamForRead()
Using (managedStream)

    ' 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)

End Using

Det här standardbeteendet för buffring är önskvärt i de flesta scenarier där du konverterar en UWP-ström till en .NET-ström. Men i vissa scenarier kanske du vill justera buffringsbeteendet för att öka prestandan.

Arbeta med stora datamängder

När du läser eller skriver större datamängder kanske du kan öka dataflödet för läsning eller skrivning genom att ange en stor buffertstorlek för AsStreamForRead, AsStreamForWriteoch AsStream tilläggsmetoder. Detta ger strömadaptern en större intern buffertstorlek. När du till exempel skickar en dataström som kommer från en stor fil till en XML-parser kan parsern göra många sekventiella små läsningar från strömmen. En stor buffert kan minska antalet anrop till den underliggande UWP-strömmen och öka prestandan.

Observera Du bör vara försiktig när du anger en buffertstorlek som är större än cirka 80 kB, eftersom detta kan orsaka fragmentering på skräpinsamlingshögen (se Förbättra prestanda för skräpinsamling). I följande kodexempel skapas en hanterad strömadapter med en buffert på 81 920 byte.

// Create a stream adapter with an 80 KB buffer.
Stream managedStream = nativeStream.AsStreamForRead(bufferSize: 81920);
' Create a stream adapter with an 80 KB buffer.
Dim managedStream As Stream = nativeStream.AsStreamForRead(bufferSize:=81920)

Metoderna Stream.CopyTo och CopyToAsync allokerar också en lokal buffert för kopiering mellan strömmar. Precis som med AsStreamForRead- tilläggsmetod kanske du kan få bättre prestanda för stora strömkopior genom att åsidosätta standardbuffertstorleken. I följande kodexempel visas hur du ändrar standardbuffertstorleken för ett CopyToAsync--anrop.

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);
Dim destination As MemoryStream = 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)

I det här exemplet används en buffertstorlek på 1 MB, vilket är större än de 80 KB som rekommenderades tidigare. Om du använder en så stor buffert kan du förbättra dataflödet för kopieringsåtgärden för mycket stora datamängder (det vill: flera hundra megabyte). Den här bufferten allokeras dock på den stora objekthögen och kan potentiellt försämra skräpinsamlingens prestanda. Du bör bara använda stora buffertstorlekar om det märkbart förbättrar appens prestanda.

När du arbetar med ett stort antal strömmar samtidigt kanske du vill minska eller eliminera buffertens minnesomkostnader. Du kan ange en mindre buffert eller ställa in bufferSize parametern till 0 för att inaktivera buffring helt för strömkortet. Du kan fortfarande uppnå bra genomströmning utan buffring om du utför stora läsningar och skrivningar till den hanterade strömmen.

Utföra svarstidskänsliga åtgärder

Du kanske också vill undvika buffring om du vill ha läsa och skriva med låg latens och inte vill läsa i stora block från den underliggande UWP-strömmen. Du kanske till exempel vill ha läsningar och skrivningar med låg latens om du använder strömmen för nätverkskommunikation.

I en chattapp kan du använda en ström via ett nätverksgränssnitt för att skicka meddelanden fram och tillbaka. I det här fallet vill du skicka meddelanden så snart de är klara och inte vänta tills bufferten fylls. Om du anger buffertstorleken till 0 när du anropar AsStreamForRead, AsStreamForWriteoch AsStream tilläggsmetoder, allokerar inte det resulterande adaptern någon buffert och alla anrop manipulerar den underliggande UWP-strömmen direkt.