Perilaku kinerja yang aneh

Saya menggunakan Visual Studio 2010 SP1, Kerangka target adalah 2.0, Target platform: CPU apa pun, pengujian di bawah Windows 7 x64 SP1.

Saya mengalami perilaku kinerja yang aneh.

Tanpa app.config, atau dengan app.config berikut, itu membuat program saya berjalan lambat (Stopwatch menunjukkan ~0,11 detik)

<?xml version="1.0"?>
<configuration>
  <startup >
    <supportedRuntime version="v2.0.50727" />
  </startup>
</configuration>

App.config berikut membuat program saya berjalan x5 kali lebih cepat (Stopwatch menunjukkan ~0,02 detik)

<?xml version="1.0"?>
<configuration>
  <startup >
    <supportedRuntime version="v4.0.30319" sku=".NETFramework,Version=v4.0" />
  </startup>
</configuration>

Ini adalah kode program pengujian:

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

class Program
{
    static void Main(string[] args)
    {
        Stopwatch sw = new Stopwatch();

        while (true)
        {
            sw.Reset();
            sw.Start();

            for (int i = 0; i < 1000000; i++ )
            {
                "blablabla".IndexOf("ngrhotbegmhroes", StringComparison.OrdinalIgnoreCase);
            }

            Console.WriteLine(sw.Elapsed);
        }
    }
}

Saya duduk berjam-jam dan tidak tahu apa yang terjadi di sini. Apakah kamu punya ide?


person DxCK    schedule 25.09.2011    source sumber
comment
Kelas System.String sendiri diubah di .NET 4. Dengan banyak pekerjaan pada bit NLS di CLR. Anda tidak dapat mengharapkan hasil serupa secara wajar, yang ada hanyalah harapan.   -  person Hans Passant    schedule 25.09.2011


Jawaban (3)


Sepertinya Anda baru saja menemukan situasi di mana .NET 4 jauh lebih cepat. Secara default, aplikasi Anda berjalan dengan kerangka kerja yang menjadi targetnya. Jika Anda memaksa menggunakan .NET 4, ini akan lebih cepat. Itu mungkin merupakan peningkatan kompiler JIT yang kebetulan sesuai dengan situasi Anda, atau mungkin merupakan peningkatan kerangka kerja - tetapi tidak terlalu mengejutkan bahwa beberapa hal menjadi lebih cepat di versi yang lebih baru.

(Untuk apa nilainya, saya akan menambah jumlah iterasi yang Anda atur waktunya jika saya jadi Anda... di kotak saya di bawah .NET 4, setiap iterasi hanya 10 md, yang sebenarnya bukan ukuran yang bagus. Saya lebih suka melakukan benchmark setidaknya selama beberapa detik.)

(Dan seperti Mitch, saya dapat memastikan bahwa saya melihat efek yang sama.)

EDIT: Saya baru saja menyelidiki ini lebih jauh, dan melihat efek yang menarik... Saya berasumsi kita menelepon haystack.IndexOf(needle, StringComparison.OrdinalIgnoreCase):

  • Di .NET 2, hasilnya kira-kira sama betapapun besarnya "jarum" tersebut
  • On .NET 4:
    • If needle is bigger than haystack (as per your example) .NET 4 is much faster than .NET 2
    • Jika needle berukuran sama dengan haystack, .NET 4 sedikit sedikit lebih lambat dibandingkan .NET 2
    • Jika needle lebih kecil dari haystack, .NET 4 banyak lebih lambat dari .NET 2

(Ini adalah pengujian di mana karakter pertama needle tidak pernah muncul di haystack, btw.)

person Jon Skeet    schedule 25.09.2011
comment
Bukankah seharusnya saat Anda memaksanya menggunakan .NET dibaca Saat Anda memaksanya menggunakan .NET 4? - person Ani; 25.09.2011
comment
Jika jarum lebih kecil dari tumpukan jerami, .NET 4 jauh lebih lambat - sepertinya optimasinya sangat buruk. - person Henk Holterman; 25.09.2011
comment
@HenkHolterman: Memang. Saya harus bergegas setelah mengujinya - jika Anda (atau orang lain) dapat mereproduksinya, itu akan sangat membantu. - person Jon Skeet; 25.09.2011

Saya baru saja menjalankan benchmark Anda dengan beberapa penyesuaian (termasuk lebih banyak iterasi dan rata-rata), dan dapat mengonfirmasi bahwa versi yang ditargetkan .NET 4.0 memang 4-5 kali lebih cepat.

Jadi mungkin IndexOf() telah dioptimalkan di .NET 4.0

person Mitch Wheat    schedule 25.09.2011

Oke, beberapa benchmark dengan VS11 baru

n = 1000000;
string haystack = "ngrhotbegmhroes";
string needle = "blablablablablablablablablangrhotbegmhrobla bla";

.NET 4.5 :  8 ms
.NET 4.0 :  8 ms
.NET 3.5 : 45 ms
.NET 2.0 : 45 ms

Jadi hasil pertama ini mengkonfirmasi temuan Anda, versi yang lebih baru lebih cepat.

Namun jauh lebih umum untuk mencari s string pendek di dalam string yang lebih besar:

n = 1000000; 
haystack = "blablablablablablablablablangrhotbegmhrobla bla";  
needle = "ngrhotbegmhroes";

.NET 4.5 : 1020 ms
.NET 4.0 : 1020 ms
.NET 3.5 :  155 ms
.NET 2.0 :  155 ms

Dan dengan tumpukan jerami yang lebih panjang (~400 karakter)

.NET 4.0 : 12100 ms
.NET 2.0 :  1700 ms

Artinya, keadaan menjadi lebih buruk untuk pola penggunaan paling umum...


Semua pengukuran dalam konfigurasi Rilis, dan Profil Klien jika tersedia.
Berjalan dari VS 11 dengan Ctrl+F5
Win 7H, Core i7 2620M

person Henk Holterman    schedule 25.09.2011
comment
wow - ini benar-benar aneh - bertanya-tanya apakah beberapa internal CLR/BCL dapat mengatakan sesuatu tentang ini... - person Random Dev; 25.09.2011
comment
Apa gunanya mencari jarum panjang di tumpukan jerami pendek? Bukankah ini memang disengaja? - person yas4891; 25.09.2011
comment
@ yas4891: Ya, tapi itu pertanyaan awal dan kinerjanya sangat berbeda. - person Henk Holterman; 25.09.2011
comment
Fwiw, .NET 4.5 tidak berdampingan, melainkan menimpa .NET 4.0. Hal yang sama dengan .NET 3.5 vs 2.0. Itu sebabnya waktunya sama. Berhati-hatilah dengan 4.5, dengan versi pra-rilis dan versi 4.0 Anda tidak dapat menarik kesimpulan yang nyata. - person Hans Passant; 25.09.2011
comment
@Hans, oke, saya hanya tahu tentang 3.5/2.0 . Harus membaca di 4.5. - person Henk Holterman; 25.09.2011