@Ulysses абсолютно прав, в приведенном примере первый вызов Milliseconds происходит после создания массивов и выполнения параллельной версии алгоритма – вот оно это всё и считает, а второй вызов корректен, считает только время работы последовательной версии.
Подправьте программу так:
var a := Arrays.CreateRandomRealMatrix(1,n);
var b := Arrays.CreateRandomRealMatrix(1,n);
var c := new real[1,n];
var d := Milliseconds;
ParallelMult(a,b,c,n);
writeln('Параллельное перемножение матриц: ',Milliseconds-d,' миллисекунд');
d := Milliseconds;
Mult(a,b,c,n);
writeln('Последовательное перемножение матриц: ',Milliseconds-d,' миллисекунд');
Если всё очень сильно утрировать, то получается такое пояснение:
В Samples пример неправильный, но для матриц это несущественно. Дело в том, что затраты на создание случайной матрицы составят O(n2) – пропорционально количеству элементов, то есть для n=400 это 4002 некоторых простых действий (создать/присвоить). Перемножение матриц потребует O(n3) действий, то есть 4003. Вот и считаем: в первом случае создаем две матрицы и перемножаем параллельно (пусть с ускорением в полтора раза – для двухъядерных процессоров сгодится), получаем: 2*4002+4003/1.5 = 4.28Е7. А последовательный алгоритм только перемножает, 4003 = 6.4Е7, то есть дольше. Разница может варьироваться в зависимости от кучи факторов, но параллельный + создание матриц всё равно быстрее последовательного.
Когда Вы перемножаете вектора, по сути, то и создание случайного вектора, и перемножение имеют сложность O(n). То есть в первом случае создаются два вектора и перемножаются – 2*400+400/1.5, а второе измерение – просто перемножение стоимостью 400. Сколько бы у вас не было ядер/потоков, тут обычное умножение всё равно быстрее создания двух векторов, и выигрыша не получите.