2012-01-19 17 views
10

Rozważmy to bardzo prosty kawałek kodu:Dlaczego ten sam kod działa szybciej w wątku?

uses Diagnostics; 

const 
    ITER_COUNT = 100000000; 

procedure TForm1.btn2Click(Sender: TObject); 
var 
    val: Double; 
    i: Integer; 
begin 
    sw := TStopwatch.StartNew; 

    val := 1; 
    for i := 0 to ITER_COUNT - 1 do 
    begin 
    val := val + i; 
    val := val - i; 
    val := val * 10; 
    val := val/10; 
    end; 

    sw.Stop; 

    mmo1.Lines.Add(Format('Simple completed in %D ms. Result: %G', 
    [sw.ElapsedMilliseconds, val])); 
end; 

Ta prosta pętla wykonuje w ms na moim komputerze. Teraz, gdy piszę ten sam kod, tylko przy użyciu innego wątku:

procedure TForm1.btn3Click(Sender: TObject); 
begin 
    sw := TStopwatch.StartNew; 
    TThread.CreateAnonymousThread(
    procedure 
    var 
     val: Double; 
     i: Integer; 
    begin 
     val := 1; 
     for i := 0 to ITER_COUNT- 1 do 
     begin 
     val := val + i; 
     val := val - i; 
     val := val * 10; 
     val := val/10; 
     end; 

     sw.Stop; 

     TThread.Queue(nil, procedure 
     begin 
      mmo1.Lines.Add(Format('Async completed in %D ms. Result: %G', 
      [sw.ElapsedMilliseconds, val])); 
     end); 
    end 
).Start; 
end; 

Ta metoda, która robi to samo, ale w innym wątku wykonuje w ms! (Skompilowany w Delphi XE z aktywną konfiguracją Release) zauważyłem ~ 25% przyrost w wątku bez względu na to, ile mam powtórzeń. Dlaczego tak się dzieje? Czy nie powinien to być ten sam rezultat?

EDIT: Po dalszych badaniach odkryłem, że prawdopodobnie powodem tego jest Windows 7 OS. Na maszynie z Windows 7 prosta pętla w głównym wątku wykonuje ~ 25% wolniej niż wersja asynchroniczna! Próbowałem nawet uruchomić ten sam projekt na tym samym komputerze z systemem Windows 7 w trybie Windows XP, a następnie oba wyniki były równe ~ 3000 ms! Jestem całkowicie zagubiony tutaj ... Co robi Windows 7 z głównym wątkiem, że jest wolniejszy?

+0

Nie można odtworzyć, czas wykonania jest taki sam dla mojego laptopa (~ 2600 ms). – kludg

+0

Nie ma dla mnie żadnej różnicy. 1947 i 1949 ms na mojej maszynie, ale jako że wciąż używam Delphi 5 jako mojego głównego środowiska programistycznego, nauczyłem się nowych rzeczy, +1 za to. –

+0

W jakim systemie OS wykonałeś swoje testy? – Linas

Odpowiedz

12

Dziwne, ale może to z powodu jakiegoś przesunięcia c.q. wyrównanie.

Być może zmienne w anonimowym wątku są odpowiednio wyrównane, a pozostałe nie. Możesz spróbować dodać kilka atrap zmiennych do zmiany na offset lub jeśli masz Delphi XE2, spróbuj innego code alignment.

+0

Udało mi się zwolnić pierwszą wersję jeszcze bardziej ze zmiennymi atrapowymi (~ 5000 ms w niektórych testach), nie mogę zrobić tego szybciej niż ~ 4000ms ... Ale to nie ma wpływu na wersję asynchroniczną ... – Linas

+0

@ Linas Make upewnij się, że 'val' jest zawsze wyrównane na granicy 8 bajtów. Na przykład przydzielić go za pomocą wywołania do GetMem, a nie na stos. –

+0

@DavidHeffernan To się udało. Jeśli ręcznie wyrekonuję moją zmienną 'Double' za pomocą pętli' GetMem', wykonam ją zgodnie z oczekiwaniami. Pytanie brzmi, dlaczego Delphi robi to poprawnie w oddzielnym wątku anonimowym, ale nie w głównym wątku? – Linas

Powiązane problemy