Mengoptimalkan akses file

Buat aplikasi WinUI dengan Windows App SDK yang mengakses sistem file secara efisien, menghindari masalah performa yang disebabkan oleh latensi disk dan memori atau penggunaan CPU yang tidak perlu.

Saat Anda ingin mengakses koleksi file yang besar dan ingin mengakses nilai properti selain properti umum seperti Nama, TipeFile, dan Jalur, akses dengan membentuk QueryOptions dan memanggil SetPropertyPrefetch. Metode SetPropertyPrefetch dapat secara dramatis meningkatkan performa aplikasi yang menampilkan kumpulan item yang diperoleh dari sistem file, seperti kumpulan gambar. Kumpulan contoh berikutnya menunjukkan beberapa cara untuk mengakses beberapa file.

Contoh pertama menggunakan Windows.Storage.StorageFolder.GetFilesAsync untuk mengambil info nama untuk sekumpulan file. Pendekatan ini memberikan performa yang baik karena contohnya hanya mengakses properti nama.

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;
}

Contoh kedua menggunakan Windows.Storage.StorageFolder.GetFilesAsync lalu mengambil properti gambar untuk setiap file. Pendekatan ini memberikan performa yang buruk.

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;
}

Contoh ketiga menggunakan QueryOptions untuk mendapatkan info tentang sekumpulan file. Pendekatan ini memberikan performa yang jauh lebih baik daripada contoh sebelumnya.

// 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"];
}

Jika Anda melakukan beberapa operasi pada objek Windows.Storage seperti Windows.Storage.ApplicationData.Current.LocalFolder, buat variabel lokal untuk mereferensikan sumber penyimpanan tersebut sehingga Anda tidak membuat ulang objek perantara setiap kali Anda mengaksesnya.

Performa streaming di C#

Pembuferan antara Aliran Data Windows Runtime dan .NET

Ada banyak skenario ketika Anda mungkin ingin mengonversi aliran Windows Runtime (seperti Windows.Storage.Streams.IInputStream atau IOutputStream) ke aliran .NET (System.IO.Stream). Misalnya, ini berguna ketika Anda menulis aplikasi WinUI dan ingin menggunakan kode .NET yang ada yang bekerja pada stream dengan Windows Storage API. Untuk mengaktifkan ini, .NET menyediakan metode ekstensi yang memungkinkan Anda mengonversi antara jenis aliran .NET dan Windows Runtime. Untuk informasi selengkapnya, lihat WindowsRuntimeStreamExtensions.

Saat Mengonversi aliran Windows Runtime ke aliran .NET, Anda secara efektif membuat adaptor untuk aliran Windows Runtime yang mendasarinya. Dalam beberapa keadaan, ada biaya runtime yang terkait dengan pemanggilan metode pada stream Windows Runtime. Ini dapat memengaruhi kecepatan aplikasi Anda, terutama dalam skenario di mana Anda melakukan banyak operasi baca atau tulis yang kecil, sering.

Untuk membantu mempercepat aplikasi, adaptor aliran Windows Runtime berisi buffer data. Sampel kode berikut menunjukkan pembacaan berurutan yang kecil menggunakan adaptor aliran Windows Runtime dengan ukuran buffer bawaan.

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);
}

Perilaku buffering default ini diinginkan dalam sebagian besar skenario di mana Anda mengonversi aliran Windows Runtime ke aliran .NET. Namun, dalam beberapa skenario Anda mungkin ingin mengubah perilaku buffering untuk meningkatkan performa.

Bekerja dengan himpunan data besar

Saat membaca atau menulis kumpulan data yang lebih besar, Anda mungkin dapat meningkatkan throughput baca atau tulis dengan memberikan ukuran buffer besar ke metode ekstensi AsStreamForRead, AsStreamForWrite, dan AsStream . Ini memberi adaptor aliran ukuran buffer internal yang lebih besar. Misalnya, saat meneruskan aliran yang berasal dari file besar ke pengurai XML, pengurai dapat membuat banyak bacaan kecil berurutan dari aliran. Buffer besar dapat mengurangi jumlah panggilan ke aliran Windows Runtime yang mendasarinya dan meningkatkan performa.

Nota

Berhati-hatilah saat mengatur ukuran buffer yang lebih besar dari sekitar 80 KB, karena ini dapat menyebabkan fragmentasi pada tumpukan pengumpul sampah. Untuk panduan terkait, lihat Meningkatkan performa pengumpulan sampah di aplikasi WinUI. Contoh kode berikut membuat adaptor aliran terkelola dengan buffer 81.920 byte.

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

Metode Stream.CopyTo dan CopyToAsync juga mengalokasikan buffer lokal untuk menyalin antar aliran. Seperti halnya metode ekstensi AsStreamForRead , Anda mungkin bisa mendapatkan performa yang lebih baik untuk salinan aliran besar dengan mengambil alih ukuran buffer default. Contoh kode berikut menunjukkan perubahan ukuran buffer default panggilan 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);

Contoh ini menggunakan ukuran buffer 1 MB, yang lebih besar dari 80 KB yang sebelumnya direkomendasikan. Menggunakan buffer besar seperti itu dapat meningkatkan throughput operasi penyalinan untuk himpunan data yang sangat besar (yaitu, beberapa ratus megabyte). Namun, buffer ini dialokasikan pada tumpukan objek besar dan berpotensi menurunkan performa pengumpulan sampah. Anda harus menggunakan ukuran buffer besar hanya jika terlihat meningkatkan performa aplikasi Anda.

Ketika Anda bekerja dengan sejumlah besar aliran secara bersamaan, Anda mungkin ingin mengurangi atau menghilangkan beban memori dari buffer. Anda dapat menentukan buffer yang lebih kecil, atau mengatur parameter bufferSize ke 0 untuk menonaktifkan buffering sepenuhnya untuk adaptor aliran tersebut. Anda masih dapat mencapai performa throughput yang baik tanpa buffering jika Anda melakukan pembacaan dan penulisan data dalam jumlah besar ke aliran terkelola.

Melakukan operasi sensitif terhadap latensi

Anda mungkin juga ingin menghindari buffering jika Anda ingin membaca dan menulis dengan latensi rendah dan tidak ingin membaca dalam blok besar dari aliran Windows Runtime dasar. Misalnya, Anda mungkin ingin pembacaan dan penulisan dengan latensi rendah jika Anda menggunakan stream untuk komunikasi jaringan.

Di aplikasi obrolan, Anda dapat menggunakan streaming melalui antarmuka jaringan untuk mengirim pesan bolak-balik. Dalam hal ini, Anda ingin mengirim pesan segera setelah siap dan tidak menunggu buffer terisi. Jika Anda mengatur ukuran buffer ke 0 saat memanggil metode ekstensi AsStreamForRead, AsStreamForWrite, dan AsStream , maka adaptor yang dihasilkan tidak akan mengalokasikan buffer, dan semua panggilan akan memanipulasi aliran Windows Runtime yang mendasarinya secara langsung.