2012-01-19 2 views
10

Рассмотрим очень простой кусок кода:Почему такой же код выполняется быстрее в потоке?

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; 

Этот простой цикл выполняется в мс на моем компьютере. Теперь, если я пишу один и тот же код, только с использованием другого потока:

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; 

Этот метод, который делает то же самое, но в другом потоке выполняется в мс! (Скомпилирован в Delphi XE с активной конфигурацией Release) Я заметил ~ 25% усиления в потоке независимо от количества итераций, которые у меня есть. Почему это так? Разве это не те же результаты?

EDIT: После дальнейших исследований я обнаружил, что причиной этого является Windows 7 OS. На машине Windows 7 простой цикл в основном потоке выполняется на ~ 25% медленнее, чем версия async! Я даже пытался запустить этот же проект на том же ПК с Windows 7 с использованием режима Windows XP, а затем оба результата были равны - ~ 3000 мс! Я полностью потерялся здесь ... Что делает Windows 7 с основным потоком, что он медленнее?

+0

Невозможно воспроизвести, время выполнения одинаково для моего ноутбука (~ 2600 мс). – kludg

+0

Никакой разницы для меня тоже. 1947 и 1949 мс на моей машине, но поскольку я все еще использую Delphi 5 в качестве основной среды разработки, я узнал кое-что новое, +1 для этого. –

+0

В какой ОС вы сделали свои тесты? – Linas

ответ

12

Странно, но, возможно, это из-за какого-то смещения c.q. выравнивание.

Возможно, переменные в анонимной нити правильно выровнены, а другая нет. Вы можете попытаться добавить некоторые фиктивные переменные для изменения в смещение, или если у вас есть Delphi XE2, попробуйте несколько разных code alignment.

+0

Мне удалось еще больше замедлить первую версию с помощью фиктивных переменных (~ 5000 мс в некоторых тестах), не может сделать это быстрее, чем ~ 4000 мс ... Но это не влияет на версию async ... – Linas

+0

@Linas Make убедитесь, что 'val' всегда выровнен на границе 8 байтов. Например, выделите его вызовом GetMem, а не в стеке. –

+0

@DavidHeffernan Это сделало трюк. Если я вручную выровняю свою переменную 'Double' с циклом GetMem, выполняется так, как ожидалось. Вопрос в том, почему Delphi делает это правильно в отдельной анонимной нити, но не в основном потоке? – Linas