Bagikan melalui


Studi Kasus: Panduan pemula untuk mengoptimalkan kode dan mengurangi biaya komputasi (C#, Visual Basic, C++, F#)

Mengurangi waktu komputasi berarti mengurangi biaya, sehingga mengoptimalkan kode Anda dapat menghemat uang. Studi kasus ini menggunakan aplikasi sampel dengan masalah performa untuk menunjukkan cara menggunakan alat pembuatan profil untuk meningkatkan efisiensi. Jika Anda ingin membandingkan alat pembuatan profil, lihat Alat mana yang harus saya pilih?

Studi kasus ini mencakup topik-topik ini:

  • Pentingnya pengoptimalan kode dan dampaknya pada pengurangan biaya komputasi.
  • Cara menggunakan alat pembuatan profil Visual Studio untuk menganalisis performa aplikasi.
  • Cara menginterpretasikan data yang disediakan oleh alat-alat ini untuk mengidentifikasi hambatan performa.
  • Cara menerapkan strategi praktis untuk mengoptimalkan kode, berfokus pada penggunaan CPU, alokasi memori, dan interaksi database.

Ikuti dan kemudian terapkan teknik ini ke aplikasi Anda sendiri untuk membuatnya lebih efisien dan hemat biaya.

Studi kasus pengoptimalan

Contoh aplikasi yang diperiksa dalam studi kasus ini adalah aplikasi .NET yang menjalankan kueri terhadap database blog dan posting blog. Ini menggunakan Kerangka Kerja Entitas, ORM populer (Pemetaan Hubungan Objek) untuk .NET, untuk berinteraksi dengan database lokal SQLite. Aplikasi ini disusun untuk menjalankan sejumlah besar kueri, mensimulasikan skenario dunia nyata di mana aplikasi .NET mungkin diperlukan untuk menangani tugas pengambilan data yang luas. Aplikasi sampel adalah versi sampel memulai Kerangka Kerja Entitas yang dimodifikasi.

Masalah performa utama dengan aplikasi sampel terletak pada caranya mengelola sumber daya komputasi dan berinteraksi dengan database. Aplikasi ini memiliki hambatan performa yang secara signifikan berdampak pada efisiensinya dan, akibatnya, biaya komputasi yang terkait dengan menjalankannya. Masalahnya termasuk gejala-gejala berikut:

  • Penggunaan CPU Tinggi: Aplikasi dapat melakukan komputasi atau tugas pemrosesan yang tidak efisien dengan cara yang tidak perlu menggunakan sejumlah besar sumber daya CPU. Hal ini dapat menyebabkan waktu respons yang lambat dan peningkatan biaya operasional.

  • Alokasi Memori Tidak Efisien: Aplikasi terkadang dapat menghadapi masalah yang terkait dengan penggunaan dan alokasi memori. Di aplikasi .NET, manajemen memori yang tidak efisien dapat menyebabkan peningkatan pengumpulan sampah, yang pada gilirannya dapat memengaruhi performa aplikasi.

  • Overhead Interaksi Database: Aplikasi yang menjalankan sejumlah besar kueri terhadap database dapat mengalami hambatan yang terkait dengan interaksi database. Ini termasuk kueri yang tidak efisien, panggilan database yang berlebihan, dan penggunaan kemampuan Kerangka Kerja Entitas yang buruk, yang semuanya dapat menurunkan performa.

Studi kasus bertujuan untuk mengatasi masalah ini dengan menggunakan alat pembuatan profil Visual Studio untuk menganalisis performa aplikasi. Dengan memahami di mana dan bagaimana performa aplikasi dapat ditingkatkan, pengembang dapat menerapkan pengoptimalan untuk mengurangi penggunaan CPU, meningkatkan efisiensi alokasi memori, menyederhanakan interaksi database, dan mengoptimalkan pemanfaatan sumber daya. Tujuan utamanya adalah untuk meningkatkan performa aplikasi secara keseluruhan, sehingga lebih efisien dan hemat biaya untuk dijalankan.

Latihan

Mengatasi masalah performa dalam sampel aplikasi .NET menghadirkan beberapa tantangan. Tantangan ini berasal dari kompleksitas diagnosis penyempitan performa. Tantangan utama dalam memperbaiki masalah yang dijelaskan adalah sebagai berikut:

  • Mendiagnosis Hambatan Performa: Salah satu tantangan utama adalah mengidentifikasi akar penyebab masalah performa secara akurat. Penggunaan CPU yang tinggi, alokasi memori yang tidak efisien, dan overhead interaksi database dapat memiliki beberapa faktor kontribusi. Pengembang harus menggunakan alat pembuatan profil secara efektif untuk mendiagnosis masalah ini, yang memerlukan beberapa pemahaman tentang cara kerja alat ini dan cara menafsirkan outputnya.

  • Kendala Pengetahuan dan Sumber Daya: Akhirnya, tim dapat menghadapi kendala yang terkait dengan pengetahuan, keahlian, dan sumber daya. Pembuatan profil dan pengoptimalan aplikasi memerlukan keterampilan dan pengalaman khusus, dan tidak semua tim mungkin memiliki akses langsung ke sumber daya ini.

Mengatasi tantangan ini memerlukan pendekatan strategis yang menggabungkan penggunaan alat pembuatan profil yang efektif, pengetahuan teknis, dan perencanaan dan pengujian yang cermat. Studi kasus bertujuan untuk memandu pengembang melalui proses ini, memberikan strategi dan wawasan untuk mengatasi tantangan ini dan meningkatkan performa aplikasi.

Strategi

Berikut adalah tampilan tingkat tinggi dari pendekatan dalam studi kasus ini:

  • Kami memulai penyelidikan dengan mengambil jejak penggunaan CPU. Alat Penggunaan CPU Visual Studio sering kali berguna untuk memulai investigasi performa dan mengoptimalkan kode untuk mengurangi biaya.
  • Selanjutnya, untuk mendapatkan wawasan tambahan untuk membantu mengisolasi masalah atau meningkatkan performa, kami mengumpulkan jejak menggunakan salah satu alat pembuatan profil lainnya. Misalnya:
    • Kami melihat penggunaan memori. Untuk .NET, kami mencoba alat Alokasi Objek .NET terlebih dahulu. (Untuk .NET atau C++, Anda dapat melihat alat Penggunaan Memori sebagai gantinya.)
    • Untuk ADO.NET atau Kerangka Kerja Entitas, kita dapat menggunakan alat Database untuk memeriksa kueri SQL, waktu kueri yang tepat, dan banyak lagi.

Pengumpulan data memerlukan tugas berikut:

  • Mengatur aplikasi ke build Rilis.
  • Memilih alat Penggunaan CPU dari Profiler Performa (Alt+F2). (Langkah selanjutnya melibatkan beberapa alat lainnya.)
  • Dari Profiler Performa, mulai aplikasi dan kumpulkan jejak.

Memeriksa area penggunaan CPU yang tinggi

Setelah mengumpulkan jejak dengan alat Penggunaan CPU dan memuatnya ke Visual Studio, kami terlebih dahulu memeriksa halaman laporan .diagsession awal yang menampilkan data ringkasan. Gunakan tautan Buka detail dalam laporan.

Cuplikan layar detail pembukaan di alat Penggunaan CPU.

Dalam tampilan detail laporan, buka tampilan Pohon Panggilan. Jalur kode dengan penggunaan CPU tertinggi di aplikasi disebut jalur panas. Ikon nyala jalur panas (Cuplikan layar yang memperlihatkan ikon Jalur Panas.) dapat membantu mengidentifikasi masalah performa yang mungkin ditingkatkan dengan cepat.

Dalam tampilan Pohon Panggilan, Anda dapat melihat penggunaan CPU yang tinggi untuk GetBlogTitleX metode di aplikasi, menggunakan sekitar 60% bagian dari penggunaan CPU aplikasi. Namun, nilai CPU Mandiri untuk GetBlogTitleX rendah, hanya sekitar .10%. Tidak seperti Total CPU, nilai CPU Mandiri mengecualikan waktu yang dihabiskan dalam fungsi lain, jadi kita tahu untuk melihat lebih jauh ke bawah pohon panggilan untuk hambatan nyata.

Cuplikan layar tampilan Pohon Panggilan di alat Penggunaan CPU.

GetBlogTitleXmelakukan panggilan eksternal ke dua DLL LINQ, yang menggunakan sebagian besar waktu CPU, sebagaimana dibuktikan oleh nilai CPU Mandiri yang sangat tinggi. Ini adalah petunjuk pertama bahwa kueri LINQ mungkin merupakan area untuk dioptimalkan.

Cuplikan layar tampilan Pohon Panggilan di alat Penggunaan CPU dengan CPU Mandiri disorot.

Untuk mendapatkan pohon panggilan yang divisualisasikan dan tampilan data yang berbeda, buka tampilan Grafik Api. (Atau, klik GetBlogTitleX kanan dan pilih Tampilkan di Grafik Api.) Di sini lagi, sepertinya GetBlogTitleX metode ini bertanggung jawab atas banyak penggunaan CPU aplikasi (ditampilkan dalam warna kuning). Panggilan eksternal ke DLL LINQ muncul di bawah GetBlogTitleX kotak, dan mereka menggunakan semua waktu CPU untuk metode tersebut.

Cuplikan layar tampilan Grafik Api di alat Penggunaan CPU.

Mengumpulkan data tambahan

Seringkali, alat lain dapat memberikan informasi tambahan untuk membantu analisis dan mengisolasi masalah. Dalam studi kasus ini, kami mengambil pendekatan berikut:

  • Pertama, lihat penggunaan memori. Mungkin ada korelasi antara penggunaan CPU yang tinggi dan penggunaan memori yang tinggi, sehingga dapat membantu untuk melihat keduanya untuk mengisolasi masalah.
  • Karena kami mengidentifikasi DLL LINQ, kami juga akan melihat alat Database.

Periksa penggunaan memori

Untuk melihat apa yang terjadi dengan aplikasi dalam hal penggunaan memori, kami mengumpulkan jejak menggunakan alat Alokasi Objek .NET (Untuk C++, Anda dapat menggunakan alat Penggunaan Memori sebagai gantinya). Tampilan Pohon Panggilan dalam jejak memori menunjukkan jalur panas dan membantu kami mengidentifikasi area penggunaan memori tinggi. Tidak mengherankan pada saat ini, metode ini GetBlogTitleX tampaknya menghasilkan banyak objek! Lebih dari 900.000 alokasi objek, pada kenyataannya.

Cuplikan layar tampilan Pohon Panggilan di alat Alokasi Objek .NET.

Sebagian besar objek yang dibuat adalah string, array objek, dan Int32s. Kita mungkin dapat melihat bagaimana jenis ini dihasilkan dengan memeriksa kode sumber.

Periksa kueri di alat Database

Di Profiler Performa, kami memilih alat Database alih-alih Penggunaan CPU (atau, pilih keduanya). Setelah mengumpulkan jejak, buka tab Kueri di halaman diagnostik. Di tab Kueri untuk jejak Database, Anda bisa melihat baris pertama memperlihatkan kueri terpanjang, 2446 mdtk. Kolom Rekaman memperlihatkan berapa banyak rekaman yang dibaca kueri. Anda dapat menggunakan informasi ini untuk perbandingan nanti.

Cuplikan layar kueri Database di alat Database.

Dengan memeriksa pernyataan yang SELECT dihasilkan oleh LINQ di kolom Kueri, kami mengidentifikasi baris pertama sebagai kueri yang terkait dengan GetBlogTitleX metode . Untuk menampilkan string kueri lengkap, perluas lebar kolom. String kueri lengkapnya adalah:

SELECT "b"."Url", "b"."BlogId", "p"."PostId", "p"."Author", "p"."BlogId", "p"."Content", "p"."Date", "p"."MetaData", "p"."Title"
FROM "Blogs" AS "b" LEFT JOIN "Posts" AS "p" ON "b"."BlogId" = "p"."BlogId" ORDER BY "b"."BlogId"

Perhatikan bahwa aplikasi mengambil banyak nilai kolom di sini, mungkin lebih dari yang kita butuhkan. Mari kita lihat kode sumbernya.

Optimalkan kode

Saatnya untuk melihat GetBlogTitleX kode sumber. Di alat Database, klik kanan kueri dan pilih Buka File Sumber. Dalam kode sumber untuk GetBlogTitleX, kami menemukan kode berikut yang menggunakan LINQ untuk membaca database.

foreach (var blog in db.Blogs.Select(b => new { b.Url, b.Posts }).ToList())
  {
    foreach (var post in blog.Posts)
    {
      if (post.Author == "Fred Smith")
      {
        Console.WriteLine($"Post: {post.Title}");
      }
  }
}

Kode ini menggunakan foreach perulangan untuk mencari database untuk blog apa pun dengan "Fred Smith" sebagai penulis. Melihatnya, Anda dapat melihat bahwa banyak objek dihasilkan dalam memori: array objek baru untuk setiap blog dalam database, string terkait untuk setiap URL, dan nilai untuk properti yang terkandung dalam postingan, seperti ID blog.

Kami melakukan sedikit penelitian dan menemukan beberapa rekomendasi umum tentang cara mengoptimalkan kueri LINQ dan membuat kode ini.

Tip

Atau, kita dapat menghemat waktu dan membiarkan Copilot melakukan penelitian untuk kita.

foreach (var x in db.Posts.Where(p => p.Author.Contains("Fred Smith")).Select(b => b.Title).ToList())
{
  Console.WriteLine("Post: " + x);
}

Dalam kode ini, kami membuat beberapa perubahan untuk membantu mengoptimalkan kueri:

  • Where Menambahkan klausul dan menghilangkan salah satu perulanganforeach.
  • Hanya memproyeksikan properti Judul dalam Select pernyataan, yang hanya kita butuhkan dalam contoh ini.

Selanjutnya, kami mencoba kembali menggunakan alat pembuatan profil.

Optimalkan kode dengan Copilot

Jika kita menggunakan Copilot, kita dapat meminta Copilot untuk meneliti masalah performa bagi kita. Pilih Minta Salinan dari menu konteks dan ketik pertanyaan berikut:

Can you make the LINQ query in this method faster?

Tip

Anda dapat menggunakan perintah garis miring seperti /optimize untuk membantu membentuk pertanyaan yang baik untuk Copilot.

Dalam contoh ini, Copilot memberikan perubahan kode yang disarankan berikut, mirip dengan kueri yang dioptimalkan, bersama dengan penjelasan.

public void GetBlogTitleX()
{
    var posts = db.Posts
        .Where(post => post.Author == "Fred Smith")
        .Select(post => post.Title)
        .ToList();

    foreach (var postTitle in posts)
    {
        Console.WriteLine($"Post: {postTitle}");
    }
}

Hasil

Setelah memperbarui kode, kami menjalankan kembali alat Penggunaan CPU untuk mengumpulkan jejak. Tampilan Pohon Panggilan menunjukkan bahwa GetBlogTitleX hanya berjalan 1754 ms, menggunakan 37% dari total CPU aplikasi, peningkatan signifikan dari 59%.

Cuplikan layar penggunaan CPU yang ditingkatkan dalam tampilan Pohon Panggilan alat Penggunaan CPU.

Beralih ke tampilan Grafik Api untuk melihat visualisasi lain yang memperlihatkan penyempurnaan. Dalam tampilan ini, GetBlogTitleX juga menggunakan bagian CPU yang lebih kecil.

Cuplikan layar penggunaan CPU yang ditingkatkan dalam tampilan Grafik Api alat Penggunaan CPU.

Periksa hasilnya di pelacakan alat Database, dan hanya dua rekaman yang dibaca menggunakan kueri ini, bukan 100.000! Selain itu, kueri jauh disederhanakan dan menghilangkan LEFT JOIN yang tidak perlu yang dihasilkan sebelumnya.

Cuplikan layar waktu kueri yang lebih cepat di alat Database.

Selanjutnya, kami memeriksa ulang hasilnya di alat Alokasi Objek .NET, dan melihat bahwa GetBlogTitleX hanya bertanggung jawab atas 56.000 alokasi objek, hampir pengurangan 95% dari 900.000!

Cuplikan layar pengurangan alokasi memori di alat Alokasi Objek .NET.

Iterate

Beberapa pengoptimalan mungkin diperlukan dan kami dapat terus melakukan iterasi dengan perubahan kode untuk melihat perubahan mana yang meningkatkan performa dan membantu mengurangi biaya komputasi.

Langkah berikutnya

Artikel dan posting blog berikut ini menyediakan informasi selengkapnya untuk membantu Anda belajar menggunakan alat performa Visual Studio secara efektif.